summaryrefslogtreecommitdiff
path: root/chromium/ui/views/widget
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/ui/views/widget
downloadqtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz
Initial import.
Diffstat (limited to 'chromium/ui/views/widget')
-rw-r--r--chromium/ui/views/widget/aero_tooltip_manager.cc116
-rw-r--r--chromium/ui/views/widget/aero_tooltip_manager.h59
-rw-r--r--chromium/ui/views/widget/child_window_message_processor.cc28
-rw-r--r--chromium/ui/views/widget/child_window_message_processor.h47
-rw-r--r--chromium/ui/views/widget/desktop_aura/OWNERS5
-rw-r--r--chromium/ui/views/widget/desktop_aura/README.chromium2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_activation_client.cc190
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_activation_client.h90
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc88
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client.h44
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc231
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h40
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc63
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc34
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h31
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc923
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h230
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc77
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h59
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc139
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h81
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h26
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_layout_manager.cc56
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_layout_manager.h49
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc91
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h69
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc884
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h264
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h123
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h29
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc885
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h266
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc1351
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h269
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen.h22
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc97
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h35
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc85
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc71
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.h31
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc146
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc128
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h66
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc63
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h63
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc155
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h62
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h31
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc176
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h69
-rw-r--r--chromium/ui/views/widget/drop_helper.cc156
-rw-r--r--chromium/ui/views/widget/drop_helper.h107
-rw-r--r--chromium/ui/views/widget/drop_target_win.cc63
-rw-r--r--chromium/ui/views/widget/drop_target_win.h55
-rw-r--r--chromium/ui/views/widget/monitor_win.cc38
-rw-r--r--chromium/ui/views/widget/monitor_win.h32
-rw-r--r--chromium/ui/views/widget/native_widget.h44
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc1078
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h228
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc412
-rw-r--r--chromium/ui/views/widget/native_widget_aura_window_observer.cc52
-rw-r--r--chromium/ui/views/widget/native_widget_aura_window_observer.h46
-rw-r--r--chromium/ui/views/widget/native_widget_delegate.h145
-rw-r--r--chromium/ui/views/widget/native_widget_private.h225
-rw-r--r--chromium/ui/views/widget/native_widget_unittest.cc100
-rw-r--r--chromium/ui/views/widget/native_widget_win.cc1040
-rw-r--r--chromium/ui/views/widget/native_widget_win.h274
-rw-r--r--chromium/ui/views/widget/native_widget_win_unittest.cc83
-rw-r--r--chromium/ui/views/widget/root_view.cc707
-rw-r--r--chromium/ui/views/widget/root_view.h226
-rw-r--r--chromium/ui/views/widget/tooltip_manager.cc65
-rw-r--r--chromium/ui/views/widget/tooltip_manager.h71
-rw-r--r--chromium/ui/views/widget/tooltip_manager_aura.cc109
-rw-r--r--chromium/ui/views/widget/tooltip_manager_aura.h49
-rw-r--r--chromium/ui/views/widget/tooltip_manager_win.cc399
-rw-r--r--chromium/ui/views/widget/tooltip_manager_win.h153
-rw-r--r--chromium/ui/views/widget/widget.cc1410
-rw-r--r--chromium/ui/views/widget/widget.h858
-rw-r--r--chromium/ui/views/widget/widget_aura_utils.cc34
-rw-r--r--chromium/ui/views/widget/widget_aura_utils.h20
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc194
-rw-r--r--chromium/ui/views/widget/widget_delegate.h201
-rw-r--r--chromium/ui/views/widget/widget_deletion_observer.cc32
-rw-r--r--chromium/ui/views/widget/widget_deletion_observer.h37
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.cc162
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.h35
-rw-r--r--chromium/ui/views/widget/widget_observer.h52
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc2116
-rw-r--r--chromium/ui/views/widget/window_reorderer.cc201
-rw-r--r--chromium/ui/views/widget/window_reorderer.h59
-rw-r--r--chromium/ui/views/widget/window_reorderer_unittest.cc263
93 files changed, 19918 insertions, 0 deletions
diff --git a/chromium/ui/views/widget/aero_tooltip_manager.cc b/chromium/ui/views/widget/aero_tooltip_manager.cc
new file mode 100644
index 00000000000..b1719def27f
--- /dev/null
+++ b/chromium/ui/views/widget/aero_tooltip_manager.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/aero_tooltip_manager.h"
+
+#include <windows.h>
+#include <commctrl.h>
+#include <shlobj.h>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/win/dpi.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/gfx/point.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager, public:
+
+AeroTooltipManager::AeroTooltipManager(Widget* widget)
+ : TooltipManagerWin(widget),
+ initial_delay_(0) {
+}
+
+AeroTooltipManager::~AeroTooltipManager() {
+ if (initial_timer_)
+ initial_timer_->Disown();
+}
+
+void AeroTooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+ if (u_msg == WM_MOUSELEAVE) {
+ last_mouse_pos_.SetPoint(-1, -1);
+ UpdateTooltip();
+ return;
+ }
+
+ if (initial_timer_)
+ initial_timer_->Disown();
+
+ if (u_msg == WM_MOUSEMOVE || u_msg == WM_NCMOUSEMOVE) {
+ gfx::Point mouse_pos_in_pixels(l_param);
+ gfx::Point mouse_pos = ui::win::ScreenToDIPPoint(mouse_pos_in_pixels);
+ if (u_msg == WM_NCMOUSEMOVE) {
+ // NC message coordinates are in screen coordinates.
+ POINT temp = mouse_pos_in_pixels.ToPOINT();
+ ::MapWindowPoints(HWND_DESKTOP, GetParent(), &temp, 1);
+ mouse_pos_in_pixels.SetPoint(temp.x, temp.y);
+ mouse_pos = ui::win::ScreenToDIPPoint(mouse_pos_in_pixels);
+ }
+ if (last_mouse_pos_ != mouse_pos) {
+ last_mouse_pos_ = mouse_pos;
+ HideKeyboardTooltip();
+ UpdateTooltip(mouse_pos);
+ }
+
+ // Delay opening of the tooltip just in case the user moves their
+ // mouse to another control. We defer this from Init because we get
+ // zero if we query it too soon.
+ if (!initial_delay_) {
+ initial_delay_ = static_cast<int>(
+ ::SendMessage(tooltip_hwnd_, TTM_GETDELAYTIME, TTDT_INITIAL, 0));
+ }
+ initial_timer_ = new InitialTimer(this);
+ initial_timer_->Start(initial_delay_);
+ } else {
+ // Hide the tooltip and cancel any timers.
+ ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, false, (LPARAM)&toolinfo_);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager, private:
+
+void AeroTooltipManager::OnTimer() {
+ initial_timer_ = NULL;
+
+ POINT pt = last_mouse_pos_.ToPOINT();
+ ::ClientToScreen(GetParent(), &pt);
+
+ // Set the position and visibility.
+ if (!tooltip_showing_) {
+ ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+ ::SendMessage(tooltip_hwnd_, TTM_TRACKPOSITION, 0, MAKELPARAM(pt.x, pt.y));
+ ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, true, (LPARAM)&toolinfo_);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager::InitialTimer
+
+AeroTooltipManager::InitialTimer::InitialTimer(AeroTooltipManager* manager)
+ : manager_(manager) {
+}
+
+void AeroTooltipManager::InitialTimer::Start(int time) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&InitialTimer::Execute, this),
+ base::TimeDelta::FromMilliseconds(time));
+}
+
+void AeroTooltipManager::InitialTimer::Disown() {
+ manager_ = NULL;
+}
+
+void AeroTooltipManager::InitialTimer::Execute() {
+ if (manager_)
+ manager_->OnTimer();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/aero_tooltip_manager.h b/chromium/ui/views/widget/aero_tooltip_manager.h
new file mode 100644
index 00000000000..0f9db20faa4
--- /dev/null
+++ b/chromium/ui/views/widget/aero_tooltip_manager.h
@@ -0,0 +1,59 @@
+// 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_VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
+#define UI_VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/views/widget/tooltip_manager_win.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager
+//
+// Default Windows tooltips are broken when using our custom window frame
+// - as soon as the tooltip receives a WM_MOUSEMOVE event, it starts spewing
+// NCHITTEST messages at its parent window (us). These messages have random
+// x/y coordinates and can't be ignored, as the DwmDefWindowProc uses
+// NCHITTEST messages to determine how to highlight the caption buttons
+// (the buttons then flicker as the hit tests sent by the user's mouse
+// trigger different effects to those sent by the tooltip).
+//
+// So instead, we have to partially implement tooltips ourselves using
+// TTF_TRACKed tooltips.
+//
+// TODO(glen): Resolve this with Microsoft.
+class AeroTooltipManager : public TooltipManagerWin {
+ public:
+ explicit AeroTooltipManager(Widget* widget);
+ virtual ~AeroTooltipManager();
+
+ virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+
+ private:
+ void OnTimer();
+
+ class InitialTimer : public base::RefCounted<InitialTimer> {
+ public:
+ explicit InitialTimer(AeroTooltipManager* manager);
+ void Start(int time);
+ void Disown();
+ void Execute();
+
+ private:
+ friend class base::RefCounted<InitialTimer>;
+
+ ~InitialTimer() {}
+
+ AeroTooltipManager* manager_;
+ };
+
+ int initial_delay_;
+ scoped_refptr<InitialTimer> initial_timer_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
diff --git a/chromium/ui/views/widget/child_window_message_processor.cc b/chromium/ui/views/widget/child_window_message_processor.cc
new file mode 100644
index 00000000000..dc497560093
--- /dev/null
+++ b/chromium/ui/views/widget/child_window_message_processor.cc
@@ -0,0 +1,28 @@
+// 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/views/widget/child_window_message_processor.h"
+
+#include "base/logging.h"
+#include "ui/base/view_prop.h"
+
+namespace views {
+
+static const char* const kChildWindowKey = "__CHILD_WINDOW_MESSAGE_PROCESSOR__";
+
+// static
+ui::ViewProp* ChildWindowMessageProcessor::Register(
+ HWND hwnd,
+ ChildWindowMessageProcessor* processor) {
+ DCHECK(processor);
+ return new ui::ViewProp(hwnd, kChildWindowKey, processor);
+}
+
+// static
+ChildWindowMessageProcessor* ChildWindowMessageProcessor::Get(HWND hwnd) {
+ return reinterpret_cast<ChildWindowMessageProcessor*>(
+ ui::ViewProp::GetValue(hwnd, kChildWindowKey));
+}
+
+} // namespace
diff --git a/chromium/ui/views/widget/child_window_message_processor.h b/chromium/ui/views/widget/child_window_message_processor.h
new file mode 100644
index 00000000000..112d9d835d4
--- /dev/null
+++ b/chromium/ui/views/widget/child_window_message_processor.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_VIEWS_WIDGET_CHILD_WINDOW_MESSAGE_PROCESSOR_H_
+#define UI_VIEWS_WIDGET_CHILD_WINDOW_MESSAGE_PROCESSOR_H_
+
+#include <windows.h>
+
+namespace ui {
+class ViewProp;
+}
+
+namespace views {
+
+// Windows sends a handful of messages to the parent window rather than the
+// window itself. For example, selection changes of a rich edit (EN_SELCHANGE)
+// are sent to the parent, not the window. Typically such message are best
+// dealt with by the window rather than the parent. NativeWidgetWin allows for
+// registering a ChildWindowMessageProcessor to handle such messages.
+class ChildWindowMessageProcessor {
+ public:
+ // Registers |processor| for |hwnd|. The caller takes ownership of the
+ // returned object.
+ static ui::ViewProp* Register(HWND hwnd,
+ ChildWindowMessageProcessor* processor);
+
+ // Returns the ChildWindowMessageProcessor for |hwnd|, NULL if there isn't
+ // one.
+ static ChildWindowMessageProcessor* Get(HWND hwnd);
+
+ // Invoked for any messages that are sent to the parent and originated from
+ // the HWND this ChildWindowMessageProcessor was registered for. Returns true
+ // if the message was handled with a valid result in |result|. Returns false
+ // if the message was not handled.
+ virtual bool ProcessMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) = 0;
+
+ protected:
+ virtual ~ChildWindowMessageProcessor() {}
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_CHILD_WINDOW_MESSAGE_PROCESSOR_H_
diff --git a/chromium/ui/views/widget/desktop_aura/OWNERS b/chromium/ui/views/widget/desktop_aura/OWNERS
new file mode 100644
index 00000000000..89630b157dd
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/OWNERS
@@ -0,0 +1,5 @@
+# Elliot is the owner of all the X11 stuff.
+per-file *x11.cc=erg@chromium.org
+per-file *x11.h=erg@chromium.org
+per-file x11*=erg@chromium.org
+per-file x11*=erg@chromium.org
diff --git a/chromium/ui/views/widget/desktop_aura/README.chromium b/chromium/ui/views/widget/desktop_aura/README.chromium
new file mode 100644
index 00000000000..5e0ff711590
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/README.chromium
@@ -0,0 +1,2 @@
+This directory contains the views::NativeWidget implementation used for the
+Desktop Aura port, and required supporting infrastructure.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_activation_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_activation_client.cc
new file mode 100644
index 00000000000..dc8f062cc32
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_activation_client.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_activation_client.h"
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/client/activation_delegate.h"
+#include "ui/aura/client/activation_change_observer.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+
+namespace views {
+
+namespace {
+
+aura::Window* FindFocusableWindowFor(aura::Window* window) {
+ while (window && !window->CanFocus())
+ window = window->parent();
+ return window;
+}
+
+} // namespace
+
+DesktopActivationClient::DesktopActivationClient(aura::RootWindow* root_window)
+ : root_window_(root_window),
+ current_active_(NULL),
+ updating_activation_(false),
+ observer_manager_(this) {
+ aura::client::GetFocusClient(root_window_)->AddObserver(this);
+ aura::client::SetActivationClient(root_window_, this);
+ root_window->AddPreTargetHandler(this);
+}
+
+DesktopActivationClient::~DesktopActivationClient() {
+ root_window_->RemovePreTargetHandler(this);
+ aura::client::GetFocusClient(root_window_)->RemoveObserver(this);
+ aura::client::SetActivationClient(root_window_, NULL);
+}
+
+void DesktopActivationClient::AddObserver(
+ aura::client::ActivationChangeObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void DesktopActivationClient::RemoveObserver(
+ aura::client::ActivationChangeObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void DesktopActivationClient::ActivateWindow(aura::Window* window) {
+ // Prevent recursion when called from focus.
+ if (updating_activation_)
+ return;
+
+ base::AutoReset<bool> in_activate_window(&updating_activation_, true);
+ // Nothing may actually have changed.
+ if (current_active_ == window)
+ return;
+ // The stacking client may impose rules on what window configurations can be
+ // activated or deactivated.
+ if (window && !CanActivateWindow(window))
+ return;
+ // Switch internal focus before we change the activation. Will probably cause
+ // recursion.
+ if (window &&
+ !window->Contains(aura::client::GetFocusClient(window)->
+ GetFocusedWindow())) {
+ aura::client::GetFocusClient(window)->FocusWindow(window);
+ }
+
+ aura::Window* old_active = current_active_;
+ current_active_ = window;
+ if (window && !observer_manager_.IsObserving(window))
+ observer_manager_.Add(window);
+
+ FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
+ observers_,
+ OnWindowActivated(window, old_active));
+ aura::client::ActivationChangeObserver* observer =
+ aura::client::GetActivationChangeObserver(old_active);
+ if (observer)
+ observer->OnWindowActivated(window, old_active);
+ observer = aura::client::GetActivationChangeObserver(window);
+ if (observer)
+ observer->OnWindowActivated(window, old_active);
+}
+
+void DesktopActivationClient::DeactivateWindow(aura::Window* window) {
+ if (window == current_active_)
+ current_active_ = NULL;
+}
+
+aura::Window* DesktopActivationClient::GetActiveWindow() {
+ return current_active_;
+}
+
+aura::Window* DesktopActivationClient::GetActivatableWindow(
+ aura::Window* window) {
+ aura::Window* parent = window->parent();
+ aura::Window* child = window;
+ while (parent) {
+ if (CanActivateWindow(child))
+ return child;
+ // If |child| isn't activatable, but has transient parent, trace
+ // that path instead.
+ if (child->transient_parent())
+ return GetActivatableWindow(child->transient_parent());
+ parent = parent->parent();
+ child = child->parent();
+ }
+ return NULL;
+}
+
+aura::Window* DesktopActivationClient::GetToplevelWindow(aura::Window* window) {
+ aura::Window* parent = window->parent();
+ aura::Window* child = window;
+ aura::Window* root = child->GetRootWindow();
+ while (parent) {
+ if (parent == root)
+ return child;
+ parent = parent->parent();
+ child = child->parent();
+ }
+ return NULL;
+}
+
+bool DesktopActivationClient::OnWillFocusWindow(aura::Window* window,
+ const ui::Event* event) {
+ return CanActivateWindow(GetActivatableWindow(window));
+}
+
+void DesktopActivationClient::OnWindowDestroying(aura::Window* window) {
+ if (current_active_ == window) {
+ current_active_ = NULL;
+ FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
+ observers_,
+ OnWindowActivated(NULL, window));
+
+ // ash::ActivationController will also activate the next window here; we
+ // don't do this because that's the desktop environment's job.
+ }
+ observer_manager_.Remove(window);
+}
+
+void DesktopActivationClient::OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ if (gained_focus)
+ ActivateWindow(GetActivatableWindow(gained_focus));
+}
+
+bool DesktopActivationClient::CanActivateWindow(aura::Window* window) const {
+ return window &&
+ window->IsVisible() &&
+ (!aura::client::GetActivationDelegate(window) ||
+ aura::client::GetActivationDelegate(window)->ShouldActivate());
+}
+
+void DesktopActivationClient::OnKeyEvent(ui::KeyEvent* event) {
+}
+
+void DesktopActivationClient::OnMouseEvent(ui::MouseEvent* event) {
+ if (event->type() == ui::ET_MOUSE_PRESSED)
+ FocusWindowWithEvent(event);
+}
+
+void DesktopActivationClient::OnScrollEvent(ui::ScrollEvent* event) {
+}
+
+void DesktopActivationClient::OnTouchEvent(ui::TouchEvent* event) {
+}
+
+void DesktopActivationClient::OnGestureEvent(ui::GestureEvent* event) {
+ if (event->type() == ui::ET_GESTURE_BEGIN &&
+ event->details().touch_points() == 1) {
+ FocusWindowWithEvent(event);
+ }
+}
+
+void DesktopActivationClient::FocusWindowWithEvent(const ui::Event* event) {
+ aura::Window* window = static_cast<aura::Window*>(event->target());
+ if (GetActiveWindow() != window) {
+ aura::client::GetFocusClient(window)->FocusWindow(
+ FindFocusableWindowFor(window));
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_activation_client.h b/chromium/ui/views/widget/desktop_aura/desktop_activation_client.h
new file mode 100644
index 00000000000..b34181792ff
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_activation_client.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESTKOP_ACTIVATION_CLIENT_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESTKOP_ACTIVATION_CLIENT_H_
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/client/activation_client.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/root_window_observer.h"
+#include "ui/aura/window_observer.h"
+#include "ui/views/views_export.h"
+
+namespace aura {
+class FocusManager;
+class RootWindow;
+
+namespace client {
+class ActivationChangeObserver;
+}
+}
+
+namespace views {
+
+// An activation client that handles activation events in a single
+// RootWindow. Used only on the Desktop where there can be multiple RootWindow
+// objects.
+class VIEWS_EXPORT DesktopActivationClient
+ : public aura::client::ActivationClient,
+ public aura::WindowObserver,
+ public ui::EventHandler,
+ public aura::client::FocusChangeObserver {
+ public:
+ explicit DesktopActivationClient(aura::RootWindow* root_window);
+ virtual ~DesktopActivationClient();
+
+ // ActivationClient:
+ virtual void AddObserver(
+ aura::client::ActivationChangeObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ aura::client::ActivationChangeObserver* observer) OVERRIDE;
+ virtual void ActivateWindow(aura::Window* window) OVERRIDE;
+ virtual void DeactivateWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetActiveWindow() OVERRIDE;
+ virtual aura::Window* GetActivatableWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetToplevelWindow(aura::Window* window) OVERRIDE;
+ virtual bool OnWillFocusWindow(aura::Window* window,
+ const ui::Event* event) OVERRIDE;
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
+
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE;
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ private:
+ void FocusWindowWithEvent(const ui::Event* event);
+
+ aura::RootWindow* root_window_;
+
+ // The current active window.
+ aura::Window* current_active_;
+
+ // True inside ActivateWindow(). Used to prevent recursion of focus
+ // change notifications causing activation.
+ bool updating_activation_;
+
+ ObserverList<aura::client::ActivationChangeObserver> observers_;
+
+ ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopActivationClient);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESTKOP_ACTIVATION_CLIENT_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
new file mode 100644
index 00000000000..bf89a4eb916
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
+
+#include "ui/aura/root_window.h"
+
+namespace views {
+
+std::set<DesktopCaptureClient*> DesktopCaptureClient::live_capture_clients_;
+
+DesktopCaptureClient::DesktopCaptureClient(aura::RootWindow* root_window)
+ : root_window_(root_window),
+ capture_window_(NULL) {
+ aura::client::SetCaptureClient(root_window_, this);
+ live_capture_clients_.insert(this);
+}
+
+DesktopCaptureClient::~DesktopCaptureClient() {
+ live_capture_clients_.erase(this);
+ aura::client::SetCaptureClient(root_window_, NULL);
+}
+
+void DesktopCaptureClient::SetCapture(aura::Window* window) {
+ if (capture_window_ == window)
+ return;
+ if (window) {
+ // If we're actually starting capture, then cancel any touches/gestures
+ // that aren't already locked to the new window, and transfer any on the
+ // old capture window to the new one. When capture is released we have no
+ // distinction between the touches/gestures that were in the window all
+ // along (and so shouldn't be canceled) and those that got moved, so
+ // just leave them all where they are.
+ for (std::set<DesktopCaptureClient*>::iterator it =
+ live_capture_clients_.begin(); it != live_capture_clients_.end();
+ ++it) {
+ (*it)->root_window_->gesture_recognizer()->TransferEventsTo(
+ capture_window_, window);
+ }
+ }
+ aura::Window* old_capture_window = GetCaptureWindow();
+ capture_window_ = window;
+
+ if (capture_window_) {
+ root_window_->SetNativeCapture();
+
+ for (std::set<DesktopCaptureClient*>::iterator it =
+ live_capture_clients_.begin(); it != live_capture_clients_.end();
+ ++it) {
+ if (*it != this)
+ (*it)->OnOtherCaptureClientTookCapture();
+ }
+ } else {
+ root_window_->ReleaseNativeCapture();
+ }
+
+ root_window_->UpdateCapture(old_capture_window, capture_window_);
+}
+
+void DesktopCaptureClient::ReleaseCapture(aura::Window* window) {
+ if (capture_window_ != window)
+ return;
+ SetCapture(NULL);
+}
+
+aura::Window* DesktopCaptureClient::GetCaptureWindow() {
+ for (std::set<DesktopCaptureClient*>::iterator it =
+ live_capture_clients_.begin(); it != live_capture_clients_.end();
+ ++it) {
+ if ((*it)->capture_window_)
+ return (*it)->capture_window_;
+ }
+ return NULL;
+}
+
+void DesktopCaptureClient::OnOtherCaptureClientTookCapture() {
+ if (capture_window_ == NULL) {
+ // While RootWindow may not technically have capture, it will store state
+ // that needs to be cleared on capture changed regarding mouse up/down.
+ root_window_->ClearMouseHandlers();
+ }
+ else {
+ SetCapture(NULL);
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h
new file mode 100644
index 00000000000..ba126826196
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2013 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_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CAPTURE_CLIENT_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CAPTURE_CLIENT_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// A capture client which will collaborate with all other capture clients of
+// its class. When capture is changed in an instance of this capture client,
+// capture is released in all other windows.
+class VIEWS_EXPORT DesktopCaptureClient : public aura::client::CaptureClient {
+ public:
+ explicit DesktopCaptureClient(aura::RootWindow* root_window);
+ virtual ~DesktopCaptureClient();
+
+ // Overridden from client::CaptureClient:
+ virtual void SetCapture(aura::Window* window) OVERRIDE;
+ virtual void ReleaseCapture(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetCaptureWindow() OVERRIDE;
+
+ private:
+ // Called when another instance of the capture client takes capture.
+ void OnOtherCaptureClientTookCapture();
+
+ aura::RootWindow* root_window_;
+ aura::Window* capture_window_;
+
+ static std::set<DesktopCaptureClient*> live_capture_clients_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopCaptureClient);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CAPTURE_CLIENT_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc
new file mode 100644
index 00000000000..d96c4456724
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright (c) 2013 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/views/widget/desktop_aura/desktop_capture_client.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/base/events/event.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+typedef ViewsTestBase ViewTest;
+
+class DesktopCaptureClientTest : public aura::test::AuraTestBase {
+ public:
+ virtual void SetUp() OVERRIDE {
+ AuraTestBase::SetUp();
+ desktop_capture_client_.reset(new DesktopCaptureClient(root_window()));
+
+ second_root_.reset(new aura::RootWindow(
+ aura::RootWindow::CreateParams(gfx::Rect(0, 0, 800, 600))));
+ second_root_->Init();
+ second_root_->Show();
+ second_root_->SetHostSize(gfx::Size(800, 600));
+ second_desktop_capture_client_.reset(
+ new DesktopCaptureClient(second_root_.get()));
+
+ desktop_position_client_.reset(new DesktopScreenPositionClient());
+ aura::client::SetScreenPositionClient(root_window(),
+ desktop_position_client_.get());
+
+ second_desktop_position_client_.reset(new DesktopScreenPositionClient());
+ aura::client::SetScreenPositionClient(
+ second_root_.get(),
+ second_desktop_position_client_.get());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ RunAllPendingInMessageLoop();
+
+ second_desktop_position_client_.reset();
+ second_desktop_capture_client_.reset();
+
+ // Kill any active compositors before we hit the compositor shutdown paths.
+ second_root_.reset();
+
+ desktop_position_client_.reset();
+ desktop_capture_client_.reset();
+
+ AuraTestBase::TearDown();
+ }
+
+ scoped_ptr<DesktopCaptureClient> desktop_capture_client_;
+ scoped_ptr<aura::RootWindow> second_root_;
+ scoped_ptr<DesktopCaptureClient> second_desktop_capture_client_;
+ scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client_;
+ scoped_ptr<aura::client::ScreenPositionClient>
+ second_desktop_position_client_;
+};
+
+// Makes sure that internal details that are set on mouse down (such as
+// mouse_pressed_handler()) are cleared when another root window takes capture.
+TEST_F(DesktopCaptureClientTest, ResetMouseEventHandlerOnCapture) {
+ // Create a window inside the RootWindow.
+ scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
+
+ // Make a synthesized mouse down event. Ensure that the RootWindow will
+ // dispatch further mouse events to |w1|.
+ ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 5),
+ gfx::Point(5, 5), 0);
+ root_window()->AsRootWindowHostDelegate()->OnHostMouseEvent(
+ &mouse_pressed_event);
+ EXPECT_EQ(w1.get(), root_window()->mouse_pressed_handler());
+
+ // Build a window in the second RootWindow.
+ scoped_ptr<aura::Window> w2(CreateNormalWindow(2, second_root_.get(), NULL));
+
+ // The act of having the second window take capture should clear out mouse
+ // pressed handler in the first RootWindow.
+ w2->SetCapture();
+ EXPECT_EQ(NULL, root_window()->mouse_pressed_handler());
+}
+
+// Makes sure that when one window gets capture, it forces the release on the
+// other. This is needed has to be handled explicitly on Linux, and is a sanity
+// check on Windows.
+TEST_F(DesktopCaptureClientTest, ResetOtherWindowCaptureOnCapture) {
+ // Create a window inside the RootWindow.
+ scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
+ w1->SetCapture();
+ // Both capture clients should return the same capture window.
+ EXPECT_EQ(w1.get(), desktop_capture_client_->GetCaptureWindow());
+ EXPECT_EQ(w1.get(), second_desktop_capture_client_->GetCaptureWindow());
+
+ // Build a window in the second RootWindow and give it capture. Both capture
+ // clients should return the same capture window.
+ scoped_ptr<aura::Window> w2(CreateNormalWindow(2, second_root_.get(), NULL));
+ w2->SetCapture();
+ EXPECT_EQ(w2.get(), desktop_capture_client_->GetCaptureWindow());
+ EXPECT_EQ(w2.get(), second_desktop_capture_client_->GetCaptureWindow());
+}
+
+// This class provides functionality to verify whether the View instance
+// received the gesture event.
+class DesktopViewInputTest : public View {
+ public:
+ DesktopViewInputTest()
+ : received_gesture_event_(false) {}
+
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ received_gesture_event_ = true;
+ return View::OnGestureEvent(event);
+ }
+
+ // Resets state maintained by this class.
+ void Reset() {
+ received_gesture_event_ = false;
+ }
+
+ bool received_gesture_event() const { return received_gesture_event_; }
+
+ private:
+ bool received_gesture_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopViewInputTest);
+};
+
+// Tests aura::Window capture and whether gesture events are sent to the window
+// which has capture.
+// The test case creates two visible widgets and sets capture to the underlying
+// aura::Windows one by one. It then sends a gesture event and validates whether
+// the window which had capture receives the gesture.
+TEST_F(ViewTest, CaptureWindowInputEventTest) {
+ scoped_ptr<DesktopCaptureClient> desktop_capture_client1;
+ scoped_ptr<DesktopCaptureClient> desktop_capture_client2;
+ scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client1;
+ scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client2;
+
+ scoped_ptr<Widget> widget1(new Widget());
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget1->Init(params);
+ internal::RootView* root1 =
+ static_cast<internal::RootView*>(widget1->GetRootView());
+
+ desktop_capture_client1.reset(new DesktopCaptureClient(
+ widget1->GetNativeView()->GetRootWindow()));
+ desktop_position_client1.reset(new DesktopScreenPositionClient());
+ aura::client::SetScreenPositionClient(
+ widget1->GetNativeView()->GetRootWindow(),
+ desktop_position_client1.get());
+
+ DesktopViewInputTest* v1 = new DesktopViewInputTest();
+ v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+ root1->AddChildView(v1);
+ widget1->Show();
+
+ scoped_ptr<Widget> widget2(new Widget());
+
+ params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget2->Init(params);
+
+ internal::RootView* root2 =
+ static_cast<internal::RootView*>(widget2->GetRootView());
+ desktop_capture_client2.reset(new DesktopCaptureClient(
+ widget2->GetNativeView()->GetRootWindow()));
+ desktop_position_client2.reset(new DesktopScreenPositionClient());
+ aura::client::SetScreenPositionClient(
+ widget2->GetNativeView()->GetRootWindow(),
+ desktop_position_client2.get());
+
+ DesktopViewInputTest* v2 = new DesktopViewInputTest();
+ v2->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+ root2->AddChildView(v2);
+ widget2->Show();
+
+ EXPECT_FALSE(widget1->GetNativeView()->HasCapture());
+ EXPECT_FALSE(widget2->GetNativeView()->HasCapture());
+ EXPECT_EQ(desktop_capture_client1->GetCaptureWindow(),
+ reinterpret_cast<aura::Window*>(0));
+ EXPECT_EQ(desktop_capture_client2->GetCaptureWindow(),
+ reinterpret_cast<aura::Window*>(0));
+
+ widget1->GetNativeView()->SetCapture();
+ EXPECT_TRUE(widget1->GetNativeView()->HasCapture());
+ EXPECT_FALSE(widget2->GetNativeView()->HasCapture());
+ EXPECT_EQ(desktop_capture_client1->GetCaptureWindow(),
+ widget1->GetNativeView());
+ EXPECT_EQ(desktop_capture_client2->GetCaptureWindow(),
+ widget1->GetNativeView());
+
+ ui::GestureEvent g1(ui::ET_GESTURE_LONG_PRESS, 80, 80, 0,
+ base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS,
+ 0.0f, 0.0f), 0);
+ root1->DispatchGestureEvent(&g1);
+ EXPECT_TRUE(v1->received_gesture_event());
+ EXPECT_FALSE(v2->received_gesture_event());
+ v1->Reset();
+ v2->Reset();
+
+ widget2->GetNativeView()->SetCapture();
+
+ EXPECT_FALSE(widget1->GetNativeView()->HasCapture());
+ EXPECT_TRUE(widget2->GetNativeView()->HasCapture());
+ EXPECT_EQ(desktop_capture_client1->GetCaptureWindow(),
+ widget2->GetNativeView());
+ EXPECT_EQ(desktop_capture_client2->GetCaptureWindow(),
+ widget2->GetNativeView());
+
+ root2->DispatchGestureEvent(&g1);
+ EXPECT_TRUE(v2->received_gesture_event());
+ EXPECT_FALSE(v1->received_gesture_event());
+
+ widget1->CloseNow();
+ widget2->CloseNow();
+ RunPendingMessages();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
new file mode 100644
index 00000000000..c31214200ed
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2013 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_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_H_
+
+namespace aura {
+class RootWindow;
+}
+
+namespace gfx {
+class Display;
+}
+
+namespace ui {
+class CursorLoader;
+}
+
+namespace views {
+
+// An interface to optionally update the state of a cursor loader. Only used on
+// desktop AuraX11.
+class DesktopCursorLoaderUpdater {
+ public:
+ virtual ~DesktopCursorLoaderUpdater() {}
+
+ // Called when a CursorLoader is created.
+ virtual void OnCreate(aura::RootWindow* window,
+ ui::CursorLoader* loader) = 0;
+
+ // Called when the display has changed (as we may need to reload the cursor
+ // assets in response to a device scale factor or rotation change).
+ virtual void OnDisplayUpdated(const gfx::Display& display,
+ ui::CursorLoader* loader) = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DISPLAY_CHANGE_HANDLER_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc
new file mode 100644
index 00000000000..e771f69be29
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2013 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/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/base/cursor/cursors_aura.h"
+#include "ui/gfx/display.h"
+
+namespace views {
+namespace {
+
+// Cursors that we need to supply our own image resources for. This was
+// generated from webcursor_gtk.cc; any cursor that either was NOTIMPLEMENTED()
+// or already was implemented with a pixmap is on this list.
+const int kImageCursorIds[] = {
+ ui::kCursorNorthEastSouthWestResize,
+ ui::kCursorNorthWestSouthEastResize,
+ ui::kCursorVerticalText,
+ ui::kCursorCell,
+ ui::kCursorContextMenu,
+ ui::kCursorAlias,
+ ui::kCursorNoDrop,
+ ui::kCursorCopy,
+ ui::kCursorNotAllowed,
+ ui::kCursorZoomIn,
+ ui::kCursorZoomOut,
+ ui::kCursorGrab,
+ ui::kCursorGrabbing,
+};
+
+void LoadImageCursors(float device_scale_factor, ui::CursorLoader* loader) {
+ int resource_id;
+ gfx::Point point;
+ for (size_t i = 0; i < arraysize(kImageCursorIds); ++i) {
+ bool success = ui::GetCursorDataFor(kImageCursorIds[i], device_scale_factor,
+ &resource_id, &point);
+ DCHECK(success);
+ loader->LoadImageCursor(kImageCursorIds[i], resource_id, point);
+ }
+}
+
+} // namespace
+
+DesktopCursorLoaderUpdaterAuraX11::DesktopCursorLoaderUpdaterAuraX11() {}
+
+DesktopCursorLoaderUpdaterAuraX11::~DesktopCursorLoaderUpdaterAuraX11() {}
+
+void DesktopCursorLoaderUpdaterAuraX11::OnCreate(
+ aura::RootWindow* window,
+ ui::CursorLoader* loader) {
+ LoadImageCursors(window->compositor()->device_scale_factor(), loader);
+}
+
+void DesktopCursorLoaderUpdaterAuraX11::OnDisplayUpdated(
+ const gfx::Display& display,
+ ui::CursorLoader* loader) {
+ LoadImageCursors(display.device_scale_factor(), loader);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h
new file mode 100644
index 00000000000..3018c977a05
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 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_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_AURAX11_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_AURAX11_H_
+
+#include "base/compiler_specific.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+
+namespace views {
+
+// Loads the subset of aura cursors that X11 doesn't provide.
+class DesktopCursorLoaderUpdaterAuraX11 : public DesktopCursorLoaderUpdater {
+ public:
+ DesktopCursorLoaderUpdaterAuraX11();
+ virtual ~DesktopCursorLoaderUpdaterAuraX11();
+
+ // Overridden from DesktopCursorLoaderUpdater:
+ virtual void OnCreate(aura::RootWindow* window,
+ ui::CursorLoader* loader) OVERRIDE;
+ virtual void OnDisplayUpdated(const gfx::Display& display,
+ ui::CursorLoader* loader) OVERRIDE;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DISPLAY_CHANGE_HANDLER_AURAX11_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc
new file mode 100644
index 00000000000..bd4ba0229aa
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
+
+#include "base/run_loop.h"
+
+namespace views {
+
+DesktopDispatcherClient::DesktopDispatcherClient() {}
+
+DesktopDispatcherClient::~DesktopDispatcherClient() {}
+
+void DesktopDispatcherClient::RunWithDispatcher(
+ base::MessageLoop::Dispatcher* nested_dispatcher,
+ aura::Window* associated_window,
+ bool nestable_tasks_allowed) {
+ // TODO(erg): This class has been copypastad from
+ // ash/accelerators/nested_dispatcher_controller.cc. I have left my changes
+ // commented out because I don't entirely understand the implications of the
+ // change.
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ bool did_allow_task_nesting = loop->NestableTasksAllowed();
+ loop->SetNestableTasksAllowed(nestable_tasks_allowed);
+
+ // DefaultAcceleratorDispatcher dispatcher(nested_dispatcher,
+ // associated_window);
+ base::RunLoop run_loop(nested_dispatcher);
+ run_loop.Run();
+ loop->SetNestableTasksAllowed(did_allow_task_nesting);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h
new file mode 100644
index 00000000000..5e7a517cc71
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DISPATCHER_CLIENT_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DISPATCHER_CLIENT_H_
+
+#include "base/basictypes.h"
+#include "ui/aura/client/dispatcher_client.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// TODO(erg): I won't lie to you; I have no idea what this is or what it does.
+class VIEWS_EXPORT DesktopDispatcherClient
+ : public aura::client::DispatcherClient {
+ public:
+ DesktopDispatcherClient();
+ virtual ~DesktopDispatcherClient();
+
+ virtual void RunWithDispatcher(base::MessageLoop::Dispatcher* dispatcher,
+ aura::Window* associated_window,
+ bool nestable_tasks_allowed) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopDispatcherClient);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DISPATCHER_CLIENT_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
new file mode 100644
index 00000000000..1870e11f5b8
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -0,0 +1,923 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
+
+#include <X11/Xatom.h>
+
+#include "base/event_types.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
+#include "ui/base/events/event.h"
+#include "ui/base/x/selection_utils.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+
+using aura::client::DragDropDelegate;
+using ui::OSExchangeData;
+
+namespace {
+
+const int kMinXdndVersion = 5;
+
+const int kWillAcceptDrop = 1;
+const int kWantFurtherPosEvents = 2;
+
+const char kXdndActionCopy[] = "XdndActionCopy";
+const char kXdndActionMove[] = "XdndActionMove";
+const char kXdndActionLink[] = "XdndActionLink";
+
+const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER";
+const char kXdndSelection[] = "XdndSelection";
+
+const char* kAtomsToCache[] = {
+ kChromiumDragReciever,
+ "XdndActionAsk",
+ kXdndActionCopy,
+ kXdndActionLink,
+ "XdndActionList",
+ kXdndActionMove,
+ "XdndActionPrivate",
+ "XdndAware",
+ "XdndDrop",
+ "XdndEnter",
+ "XdndFinished",
+ "XdndLeave",
+ "XdndPosition",
+ "XdndProxy", // Proxy windows?
+ kXdndSelection,
+ "XdndStatus",
+ "XdndTypeList",
+ NULL
+};
+
+// Helper class to FindWindowFor which looks for a drag target under the
+// cursor.
+class DragTargetWindowFinder : public ui::EnumerateWindowsDelegate {
+ public:
+ DragTargetWindowFinder(XID ignored_icon_window,
+ gfx::Point screen_loc)
+ : ignored_icon_window_(ignored_icon_window),
+ output_window_(None),
+ screen_loc_(screen_loc) {
+ ui::EnumerateTopLevelWindows(this);
+ }
+
+ virtual ~DragTargetWindowFinder() {}
+
+ XID window() const { return output_window_; }
+
+ protected:
+ virtual bool ShouldStopIterating(XID window) OVERRIDE {
+ if (window == ignored_icon_window_)
+ return false;
+
+ if (!ui::IsWindowVisible(window))
+ return false;
+
+ if (!ui::WindowContainsPoint(window, screen_loc_))
+ return false;
+
+ if (ui::PropertyExists(window, "WM_STATE")) {
+ output_window_ = window;
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ XID ignored_icon_window_;
+ XID output_window_;
+ gfx::Point screen_loc_;
+
+ DISALLOW_COPY_AND_ASSIGN(DragTargetWindowFinder);
+};
+
+// Returns the topmost X11 window at |screen_point| if it is advertising that
+// is supports the Xdnd protocol. Will return the window under the pointer as
+// |mouse_window|. If there's a Xdnd aware window, it will be returned in
+// |dest_window|.
+void FindWindowFor(const gfx::Point& screen_point,
+ ::Window* mouse_window, ::Window* dest_window) {
+ DragTargetWindowFinder finder(None, screen_point);
+ *mouse_window = finder.window();
+ *dest_window = None;
+
+ if (finder.window() == None)
+ return;
+
+ // Figure out which window we should test as XdndAware. If mouse_window has
+ // XdndProxy, it will set that proxy on target, and if not, |target|'s
+ // original value will remain.
+ XID target = *mouse_window;
+ ui::GetXIDProperty(*mouse_window, "XdndProxy", &target);
+
+ int version;
+ if (ui::GetIntProperty(target, "XdndAware", &version) &&
+ version >= kMinXdndVersion) {
+ *dest_window = target;
+ }
+}
+
+} // namespace
+
+namespace views {
+
+std::map< ::Window, DesktopDragDropClientAuraX11*>
+ DesktopDragDropClientAuraX11::g_live_client_map;
+
+class DesktopDragDropClientAuraX11::X11DragContext :
+ public base::MessageLoop::Dispatcher {
+ public:
+ X11DragContext(ui::X11AtomCache* atom_cache,
+ ::Window local_window,
+ const XClientMessageEvent& event);
+ virtual ~X11DragContext();
+
+ // When we receive an XdndPosition message, we need to have all the data
+ // copied from the other window before we process the XdndPosition
+ // message. If we have that data already, dispatch immediately. Otherwise,
+ // delay dispatching until we do.
+ void OnStartXdndPositionMessage(DesktopDragDropClientAuraX11* client,
+ ::Window source_window,
+ const gfx::Point& screen_point);
+
+ // Called to request the next target from the source window. This is only
+ // done on the first XdndPosition; after that, we cache the data offered by
+ // the source window.
+ void RequestNextTarget();
+
+ // Called when XSelection data has been copied to our process.
+ void OnSelectionNotify(const XSelectionEvent& xselection);
+
+ // Clones the fetched targets.
+ const ui::SelectionFormatMap& fetched_targets() { return fetched_targets_; }
+
+ // Reads the "XdndActionList" property from |source_window| and copies it
+ // into |actions|.
+ void ReadActions();
+
+ // Creates a ui::DragDropTypes::DragOperation representation of the current
+ // action list.
+ int GetDragOperation() const;
+
+ private:
+ // Overridden from MessageLoop::Dispatcher:
+ virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ // The atom cache owned by our parent.
+ ui::X11AtomCache* atom_cache_;
+
+ // The XID of our chrome local aura window handling our events.
+ ::Window local_window_;
+
+ // The XID of the window that's initiated the drag.
+ unsigned long source_window_;
+
+ // The client we inform once we're done with requesting data.
+ DesktopDragDropClientAuraX11* drag_drop_client_;
+
+ // Whether we're blocking the handling of an XdndPosition message by waiting
+ // for |unfetched_targets_| to be fetched.
+ bool waiting_to_handle_position_;
+
+ // Where the cursor is on screen.
+ gfx::Point screen_point_;
+
+ // A SelectionFormatMap of data that we have in our process.
+ ui::SelectionFormatMap fetched_targets_;
+
+ // The names of various data types offered by the other window that we
+ // haven't fetched and put in |fetched_targets_| yet.
+ std::vector<Atom> unfetched_targets_;
+
+ // Possible actions.
+ std::vector<Atom> actions_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11DragContext);
+};
+
+DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
+ ui::X11AtomCache* atom_cache,
+ ::Window local_window,
+ const XClientMessageEvent& event)
+ : atom_cache_(atom_cache),
+ local_window_(local_window),
+ source_window_(event.data.l[0]),
+ drag_drop_client_(NULL),
+ waiting_to_handle_position_(false) {
+ bool get_types = ((event.data.l[1] & 1) != 0);
+
+ if (get_types) {
+ if (!ui::GetAtomArrayProperty(source_window_,
+ "XdndTypeList",
+ &unfetched_targets_)) {
+ return;
+ }
+ } else {
+ // data.l[2,3,4] contain the first three types. Unused slots can be None.
+ for (int i = 0; i < 3; ++i) {
+ if (event.data.l[2+i] != None) {
+ unfetched_targets_.push_back(event.data.l[2+i]);
+ }
+ }
+ }
+
+ DesktopDragDropClientAuraX11* client =
+ DesktopDragDropClientAuraX11::GetForWindow(source_window_);
+ if (!client) {
+ // The window doesn't have a DesktopDragDropClientAuraX11, that means it's
+ // created by some other process. Listen for messages on it.
+ base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(
+ this, source_window_);
+ XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(),
+ source_window_, PropertyChangeMask);
+
+ // We must perform a full sync here because we could be racing
+ // |source_window_|.
+ XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), False);
+ } else {
+ // This drag originates from an aura window within our process. This means
+ // that we can shortcut the X11 server and ask the owning SelectionOwner
+ // for the data it's offering.
+ fetched_targets_ = client->GetFormatMap();
+ unfetched_targets_.clear();
+ }
+
+ ReadActions();
+}
+
+DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() {
+ DesktopDragDropClientAuraX11* client =
+ DesktopDragDropClientAuraX11::GetForWindow(source_window_);
+ if (!client) {
+ // Unsubscribe from message events.
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(
+ source_window_);
+ }
+}
+
+void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
+ DesktopDragDropClientAuraX11* client,
+ ::Window source_window,
+ const gfx::Point& screen_point) {
+ DCHECK_EQ(source_window_, source_window);
+
+ if (!unfetched_targets_.empty()) {
+ // We have unfetched targets. That means we need to pause the handling of
+ // the position message and ask the other window for its data.
+ screen_point_ = screen_point;
+ drag_drop_client_ = client;
+ waiting_to_handle_position_ = true;
+
+ fetched_targets_ = ui::SelectionFormatMap();
+ RequestNextTarget();
+ } else {
+ client->CompleteXdndPosition(source_window, screen_point);
+ }
+}
+
+void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() {
+ ::Atom target = unfetched_targets_.back();
+ unfetched_targets_.pop_back();
+
+ XConvertSelection(base::MessagePumpAuraX11::GetDefaultXDisplay(),
+ atom_cache_->GetAtom(kXdndSelection),
+ target,
+ atom_cache_->GetAtom(kChromiumDragReciever),
+ local_window_,
+ CurrentTime);
+}
+
+void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify(
+ const XSelectionEvent& event) {
+ DCHECK(waiting_to_handle_position_);
+ DCHECK(drag_drop_client_);
+ DCHECK_EQ(event.property, atom_cache_->GetAtom(kChromiumDragReciever));
+
+ scoped_refptr<base::RefCountedMemory> data;
+ ::Atom type = None;
+ if (ui::GetRawBytesOfProperty(local_window_, event.property,
+ &data, NULL, NULL, &type)) {
+ fetched_targets_.Insert(event.target, data);
+ }
+
+ if (!unfetched_targets_.empty()) {
+ RequestNextTarget();
+ } else {
+ waiting_to_handle_position_ = false;
+ drag_drop_client_->CompleteXdndPosition(source_window_, screen_point_);
+ drag_drop_client_ = NULL;
+ }
+}
+
+void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() {
+ DesktopDragDropClientAuraX11* client =
+ DesktopDragDropClientAuraX11::GetForWindow(source_window_);
+ if (!client) {
+ std::vector<Atom> atom_array;
+ if (!ui::GetAtomArrayProperty(source_window_,
+ "XdndActionList",
+ &atom_array)) {
+ actions_.clear();
+ } else {
+ actions_.swap(atom_array);
+ }
+ } else {
+ // We have a property notify set up for other windows in case they change
+ // their action list. Thankfully, the views interface is static and you
+ // can't change the action list after you enter StartDragAndDrop().
+ actions_ = client->GetOfferedDragOperations();
+ }
+}
+
+int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ for (std::vector<Atom>::const_iterator it = actions_.begin();
+ it != actions_.end(); ++it) {
+ if (*it == atom_cache_->GetAtom(kXdndActionCopy))
+ drag_operation |= ui::DragDropTypes::DRAG_COPY;
+ else if (*it == atom_cache_->GetAtom(kXdndActionMove))
+ drag_operation |= ui::DragDropTypes::DRAG_MOVE;
+ else if (*it == atom_cache_->GetAtom(kXdndActionLink))
+ drag_operation |= ui::DragDropTypes::DRAG_LINK;
+ }
+
+ return drag_operation;
+}
+
+bool DesktopDragDropClientAuraX11::X11DragContext::Dispatch(
+ const base::NativeEvent& event) {
+ if (event->type == PropertyNotify &&
+ event->xproperty.atom == atom_cache_->GetAtom("XdndActionList")) {
+ ReadActions();
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
+ aura::RootWindow* root_window,
+ views::DesktopNativeCursorManager* cursor_manager,
+ Display* xdisplay,
+ ::Window xwindow)
+ : move_loop_(this),
+ root_window_(root_window),
+ xdisplay_(xdisplay),
+ xwindow_(xwindow),
+ atom_cache_(xdisplay_, kAtomsToCache),
+ target_window_(NULL),
+ source_provider_(NULL),
+ source_current_window_(None),
+ drag_drop_in_progress_(false),
+ drag_operation_(0),
+ resulting_operation_(0),
+ grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)),
+ copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)),
+ move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)) {
+ DCHECK(g_live_client_map.find(xwindow) == g_live_client_map.end());
+ g_live_client_map.insert(std::make_pair(xwindow, this));
+
+ // Mark that we are aware of drag and drop concepts.
+ unsigned long xdnd_version = kMinXdndVersion;
+ XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"),
+ XA_ATOM, 32, PropModeReplace,
+ reinterpret_cast<unsigned char*>(&xdnd_version), 1);
+}
+
+DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() {
+ g_live_client_map.erase(xwindow_);
+}
+
+// static
+DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow(
+ ::Window window) {
+ std::map< ::Window, DesktopDragDropClientAuraX11*>::const_iterator it =
+ g_live_client_map.find(window);
+ if (it == g_live_client_map.end())
+ return NULL;
+ return it->second;
+}
+
+void DesktopDragDropClientAuraX11::OnXdndEnter(
+ const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndEnter";
+
+ int version = (event.data.l[1] & 0xff000000) >> 24;
+ if (version < 3) {
+ LOG(ERROR) << "Received old XdndEnter message.";
+ return;
+ }
+
+ // Make sure that we've run ~X11DragContext() before creating another one.
+ target_current_context_.reset();
+ target_current_context_.reset(
+ new X11DragContext(&atom_cache_, xwindow_, event));
+
+ // In the Windows implementation, we immediately call DesktopDropTargetWin::
+ // Translate(). Here, we wait until we receive an XdndPosition message
+ // because the enter message doesn't convey any positioning
+ // information.
+}
+
+void DesktopDragDropClientAuraX11::OnXdndLeave(
+ const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndLeave";
+ NotifyDragLeave();
+ target_current_context_.reset();
+}
+
+void DesktopDragDropClientAuraX11::OnXdndPosition(
+ const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndPosition";
+
+ unsigned long source_window = event.data.l[0];
+ int x_root_window = event.data.l[2] >> 16;
+ int y_root_window = event.data.l[2] & 0xffff;
+
+ if (!target_current_context_.get()) {
+ NOTREACHED();
+ return;
+ }
+
+ // If we already have all the data from this drag, we complete it
+ // immediately.
+ target_current_context_->OnStartXdndPositionMessage(
+ this, source_window, gfx::Point(x_root_window, y_root_window));
+}
+
+void DesktopDragDropClientAuraX11::OnXdndStatus(
+ const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndStatus";
+
+ unsigned long source_window = event.data.l[0];
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ if (event.data.l[1] & 1) {
+ ::Atom atom_operation = event.data.l[4];
+ negotiated_operation_[source_window] = atom_operation;
+ drag_operation = AtomToDragOperation(atom_operation);
+ }
+
+ switch (drag_operation) {
+ case ui::DragDropTypes::DRAG_COPY:
+ move_loop_.UpdateCursor(copy_grab_cursor_);
+ break;
+ case ui::DragDropTypes::DRAG_MOVE:
+ move_loop_.UpdateCursor(move_grab_cursor_);
+ break;
+ default:
+ move_loop_.UpdateCursor(grab_cursor_);
+ break;
+ }
+
+ // Note: event.data.[2,3] specify a rectangle. It is a request by the other
+ // window to not send further XdndPosition messages while the cursor is
+ // within it. However, it is considered advisory and (at least according to
+ // the spec) the other side must handle further position messages within
+ // it. GTK+ doesn't bother with this, so neither should we.
+
+ waiting_on_status_.erase(source_window);
+
+ if (ContainsKey(pending_drop_, source_window)) {
+ // We were waiting on the status message so we could send the XdndDrop.
+ SendXdndDrop(source_window);
+ return;
+ }
+
+ NextPositionMap::iterator it = next_position_message_.find(source_window);
+ if (it != next_position_message_.end()) {
+ // We were waiting on the status message so we could send off the next
+ // position message we queued up.
+ gfx::Point p = it->second.first;
+ unsigned long time = it->second.second;
+ next_position_message_.erase(it);
+
+ SendXdndPosition(source_window, p, time);
+ }
+}
+
+void DesktopDragDropClientAuraX11::OnXdndFinished(
+ const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndFinished";
+ resulting_operation_ = AtomToDragOperation(
+ negotiated_operation_[event.data.l[0]]);
+ move_loop_.EndMoveLoop();
+}
+
+void DesktopDragDropClientAuraX11::OnXdndDrop(
+ const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndDrop";
+
+ unsigned long source_window = event.data.l[0];
+
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ if (target_window_) {
+ aura::client::DragDropDelegate* delegate =
+ aura::client::GetDragDropDelegate(target_window_);
+ if (delegate) {
+ ui::OSExchangeData data(new ui::OSExchangeDataProviderAuraX11(
+ xwindow_, target_current_context_->fetched_targets()));
+
+ ui::DropTargetEvent event(data,
+ target_window_location_,
+ target_window_root_location_,
+ target_current_context_->GetDragOperation());
+ drag_operation = delegate->OnPerformDrop(event);
+ }
+
+ target_window_->RemoveObserver(this);
+ target_window_ = NULL;
+ }
+
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndFinished");
+ xev.xclient.format = 32;
+ xev.xclient.window = source_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = (drag_operation != 0) ? 1 : 0;
+ xev.xclient.data.l[2] = DragOperationToAtom(drag_operation);
+
+ SendXClientEvent(source_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::OnSelectionNotify(
+ const XSelectionEvent& xselection) {
+ if (!target_current_context_) {
+ NOTIMPLEMENTED();
+ return;
+ }
+
+ target_current_context_->OnSelectionNotify(xselection);
+}
+
+int DesktopDragDropClientAuraX11::StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::RootWindow* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ source_current_window_ = None;
+ drag_drop_in_progress_ = true;
+ drag_operation_ = operation;
+ resulting_operation_ = ui::DragDropTypes::DRAG_NONE;
+
+ const ui::OSExchangeData::Provider* provider = &data.provider();
+ source_provider_ = static_cast<const ui::OSExchangeDataProviderAuraX11*>(
+ provider);
+
+ source_provider_->TakeOwnershipOfSelection();
+
+ std::vector< ::Atom> actions = GetOfferedDragOperations();
+ ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions);
+
+ // Windows has a specific method, DoDragDrop(), which performs the entire
+ // drag. We have to emulate this, so we spin off a nested runloop which will
+ // track all cursor movement and reroute events to a specific handler.
+ move_loop_.RunMoveLoop(source_window, grab_cursor_);
+
+ source_provider_ = NULL;
+ drag_drop_in_progress_ = false;
+ drag_operation_ = 0;
+ XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
+
+ return resulting_operation_;
+}
+
+void DesktopDragDropClientAuraX11::DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void DesktopDragDropClientAuraX11::Drop(aura::Window* target,
+ const ui::LocatedEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void DesktopDragDropClientAuraX11::DragCancel() {
+ move_loop_.EndMoveLoop();
+}
+
+bool DesktopDragDropClientAuraX11::IsDragDropInProgress() {
+ return drag_drop_in_progress_;
+}
+
+void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) {
+ DCHECK_EQ(target_window_, window);
+ target_window_ = NULL;
+}
+
+void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) {
+ gfx::Point screen_point(event->x_root, event->y_root);
+
+ // Find the current window the cursor is over.
+ ::Window mouse_window = None;
+ ::Window dest_window = None;
+ FindWindowFor(screen_point, &mouse_window, &dest_window);
+
+ if (source_current_window_ != dest_window) {
+ if (source_current_window_ != None)
+ SendXdndLeave(source_current_window_);
+
+ source_current_window_ = dest_window;
+
+ if (source_current_window_ != None) {
+ negotiated_operation_.erase(source_current_window_);
+ SendXdndEnter(source_current_window_);
+ }
+ }
+
+ if (source_current_window_ != None) {
+ if (ContainsKey(waiting_on_status_, dest_window)) {
+ next_position_message_[dest_window] =
+ std::make_pair(screen_point, event->time);
+ } else {
+ SendXdndPosition(dest_window, screen_point, event->time);
+ }
+ }
+}
+
+void DesktopDragDropClientAuraX11::OnMouseReleased() {
+ if (source_current_window_ != None) {
+ if (ContainsKey(waiting_on_status_, source_current_window_)) {
+ // If we are waiting for an XdndStatus message, we need to wait for it to
+ // complete.
+ pending_drop_.insert(source_current_window_);
+ return;
+ }
+
+ std::map< ::Window, ::Atom>::iterator it =
+ negotiated_operation_.find(source_current_window_);
+ if (it != negotiated_operation_.end() && it->second != None) {
+ // We have negotiated an action with the other end.
+ SendXdndDrop(source_current_window_);
+ return;
+ }
+
+ SendXdndLeave(source_current_window_);
+ source_current_window_ = None;
+ }
+
+ move_loop_.EndMoveLoop();
+}
+
+void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
+ target_current_context_.reset();
+}
+
+void DesktopDragDropClientAuraX11::DragTranslate(
+ const gfx::Point& root_window_location,
+ scoped_ptr<ui::OSExchangeData>* data,
+ scoped_ptr<ui::DropTargetEvent>* event,
+ aura::client::DragDropDelegate** delegate) {
+ gfx::Point root_location = root_window_location;
+ root_window_->ConvertPointFromNativeScreen(&root_location);
+ aura::Window* target_window =
+ root_window_->GetEventHandlerForPoint(root_location);
+ bool target_window_changed = false;
+ if (target_window != target_window_) {
+ if (target_window_)
+ NotifyDragLeave();
+ target_window_ = target_window;
+ if (target_window_)
+ target_window_->AddObserver(this);
+ target_window_changed = true;
+ }
+ *delegate = NULL;
+ if (!target_window_)
+ return;
+ *delegate = aura::client::GetDragDropDelegate(target_window_);
+ if (!*delegate)
+ return;
+
+ data->reset(new OSExchangeData(new ui::OSExchangeDataProviderAuraX11(
+ xwindow_, target_current_context_->fetched_targets())));
+ gfx::Point location = root_location;
+ aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
+
+ target_window_location_ = location;
+ target_window_root_location_ = root_location;
+
+ event->reset(new ui::DropTargetEvent(
+ *(data->get()),
+ location,
+ root_location,
+ target_current_context_->GetDragOperation()));
+ if (target_window_changed)
+ (*delegate)->OnDragEntered(*event->get());
+}
+
+void DesktopDragDropClientAuraX11::NotifyDragLeave() {
+ if (!target_window_)
+ return;
+ DragDropDelegate* delegate =
+ aura::client::GetDragDropDelegate(target_window_);
+ if (delegate)
+ delegate->OnDragExited();
+ target_window_->RemoveObserver(this);
+ target_window_ = NULL;
+}
+
+::Atom DesktopDragDropClientAuraX11::DragOperationToAtom(
+ int drag_operation) {
+ if (drag_operation & ui::DragDropTypes::DRAG_COPY)
+ return atom_cache_.GetAtom(kXdndActionCopy);
+ if (drag_operation & ui::DragDropTypes::DRAG_MOVE)
+ return atom_cache_.GetAtom(kXdndActionMove);
+ if (drag_operation & ui::DragDropTypes::DRAG_LINK)
+ return atom_cache_.GetAtom(kXdndActionLink);
+
+ return None;
+}
+
+int DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) {
+ if (atom == atom_cache_.GetAtom(kXdndActionCopy))
+ return ui::DragDropTypes::DRAG_COPY;
+ if (atom == atom_cache_.GetAtom(kXdndActionMove))
+ return ui::DragDropTypes::DRAG_MOVE;
+ if (atom == atom_cache_.GetAtom(kXdndActionLink))
+ return ui::DragDropTypes::DRAG_LINK;
+
+ return ui::DragDropTypes::DRAG_NONE;
+}
+
+std::vector< ::Atom> DesktopDragDropClientAuraX11::GetOfferedDragOperations() {
+ std::vector< ::Atom> operations;
+ if (drag_operation_ & ui::DragDropTypes::DRAG_COPY)
+ operations.push_back(atom_cache_.GetAtom(kXdndActionCopy));
+ if (drag_operation_ & ui::DragDropTypes::DRAG_MOVE)
+ operations.push_back(atom_cache_.GetAtom(kXdndActionMove));
+ if (drag_operation_ & ui::DragDropTypes::DRAG_LINK)
+ operations.push_back(atom_cache_.GetAtom(kXdndActionLink));
+ return operations;
+}
+
+ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const {
+ return source_provider_ ? source_provider_->GetFormatMap() :
+ ui::SelectionFormatMap();
+}
+
+void DesktopDragDropClientAuraX11::CompleteXdndPosition(
+ ::Window source_window,
+ const gfx::Point& screen_point) {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ scoped_ptr<ui::OSExchangeData> data;
+ scoped_ptr<ui::DropTargetEvent> drop_target_event;
+ DragDropDelegate* delegate = NULL;
+ DragTranslate(screen_point, &data, &drop_target_event, &delegate);
+ if (delegate)
+ drag_operation = delegate->OnDragUpdated(*drop_target_event);
+
+ // Sends an XdndStatus message back to the source_window. l[2,3]
+ // theoretically represent an area in the window where the current action is
+ // the same as what we're returning, but I can't find any implementation that
+ // actually making use of this. A client can return (0, 0) and/or set the
+ // first bit of l[1] to disable the feature, and it appears that gtk neither
+ // sets this nor respects it if set.
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndStatus");
+ xev.xclient.format = 32;
+ xev.xclient.window = source_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = (drag_operation != 0) ?
+ (kWantFurtherPosEvents | kWillAcceptDrop) : 0;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = DragOperationToAtom(drag_operation);
+
+ SendXClientEvent(source_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) {
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndEnter");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = (kMinXdndVersion << 24); // The version number.
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ std::vector<Atom> targets;
+ source_provider_->RetrieveTargets(&targets);
+
+ if (targets.size() > 3) {
+ xev.xclient.data.l[1] |= 1;
+ ui::SetAtomArrayProperty(xwindow_, "XdndTypeList", "ATOM", targets);
+ } else {
+ // Pack the targets into the enter message.
+ for (size_t i = 0; i < targets.size(); ++i)
+ xev.xclient.data.l[2 + i] = targets[i];
+ }
+
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) {
+ // If we're sending a leave message, don't wait for status messages anymore.
+ waiting_on_status_.erase(dest_window);
+ NextPositionMap::iterator it = next_position_message_.find(dest_window);
+ if (it != next_position_message_.end())
+ next_position_message_.erase(it);
+
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndLeave");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndPosition(
+ ::Window dest_window,
+ const gfx::Point& screen_point,
+ unsigned long time) {
+ waiting_on_status_.insert(dest_window);
+
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndPosition");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = (screen_point.x() << 16) | screen_point.y();
+ xev.xclient.data.l[3] = time;
+ xev.xclient.data.l[4] = DragOperationToAtom(drag_operation_);
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) {
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndDrop");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = CurrentTime;
+ xev.xclient.data.l[3] = None;
+ xev.xclient.data.l[4] = None;
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
+ XEvent* xev) {
+ DCHECK_EQ(ClientMessage, xev->type);
+
+ // Don't send messages to the X11 message queue if we can help it.
+ DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid);
+ if (short_circuit) {
+ Atom message_type = xev->xclient.message_type;
+ if (message_type == atom_cache_.GetAtom("XdndEnter")) {
+ short_circuit->OnXdndEnter(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
+ short_circuit->OnXdndLeave(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
+ short_circuit->OnXdndPosition(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
+ short_circuit->OnXdndStatus(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
+ short_circuit->OnXdndFinished(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
+ short_circuit->OnXdndDrop(xev->xclient);
+ return;
+ }
+ }
+
+ // I don't understand why the GTK+ code is doing what it's doing here. It
+ // goes out of its way to send the XEvent so that it receives a callback on
+ // success or failure, and when it fails, it then sends an internal
+ // GdkEvent about the failed drag. (And sending this message doesn't appear
+ // to go through normal xlib machinery, but instead passes through the low
+ // level xProto (the x11 wire format) that I don't understand.
+ //
+ // I'm unsure if I have to jump through those hoops, or if XSendEvent is
+ // sufficient.
+ XSendEvent(xdisplay_, xid, False, 0, xev);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
new file mode 100644
index 00000000000..2dee7305f2f
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -0,0 +1,230 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
+
+#include <X11/Xlib.h>
+
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include <set>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/x/x11_atom_cache.h"
+#include "ui/gfx/point.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
+
+namespace aura {
+class RootWindow;
+namespace client {
+class DragDropDelegate;
+}
+}
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+class DragSource;
+class DropTargetEvent;
+class OSExchangeData;
+class OSExchangeDataProviderAuraX11;
+class RootWindow;
+class SelectionFormatMap;
+}
+
+namespace views {
+class DesktopNativeCursorManager;
+
+// Implements drag and drop on X11 for aura. On one side, this class takes raw
+// X11 events forwarded from DesktopRootWindowHostLinux, while on the other, it
+// handles the views drag events.
+class VIEWS_EXPORT DesktopDragDropClientAuraX11
+ : public aura::client::DragDropClient,
+ public aura::WindowObserver,
+ public X11WholeScreenMoveLoopDelegate {
+ public:
+ DesktopDragDropClientAuraX11(
+ aura::RootWindow* root_window,
+ views::DesktopNativeCursorManager* cursor_manager,
+ Display* xdisplay,
+ ::Window xwindow);
+ virtual ~DesktopDragDropClientAuraX11();
+
+ // We maintain a mapping of live DesktopDragDropClientAuraX11 objects to
+ // their ::Windows. We do this so that we're able to short circuit sending
+ // X11 messages to windows in our process.
+ static DesktopDragDropClientAuraX11* GetForWindow(::Window window);
+
+ // These methods handle the various X11 client messages from the platform.
+ void OnXdndEnter(const XClientMessageEvent& event);
+ void OnXdndLeave(const XClientMessageEvent& event);
+ void OnXdndPosition(const XClientMessageEvent& event);
+ void OnXdndStatus(const XClientMessageEvent& event);
+ void OnXdndFinished(const XClientMessageEvent& event);
+ void OnXdndDrop(const XClientMessageEvent& event);
+
+ // Called when XSelection data has been copied to our process.
+ void OnSelectionNotify(const XSelectionEvent& xselection);
+
+ // Overridden from aura::client::DragDropClient:
+ virtual int StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::RootWindow* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) OVERRIDE;
+ virtual void Drop(aura::Window* target,
+ const ui::LocatedEvent& event) OVERRIDE;
+ virtual void DragCancel() OVERRIDE;
+ virtual bool IsDragDropInProgress() OVERRIDE;
+
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ // Overridden from X11WholeScreenMoveLoopDelegate:
+ virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
+ virtual void OnMouseReleased() OVERRIDE;
+ virtual void OnMoveLoopEnded() OVERRIDE;
+
+ private:
+ typedef std::map< ::Window, std::pair<gfx::Point, unsigned long> >
+ NextPositionMap;
+
+ // When we receive an position x11 message, we need to translate that into
+ // the underlying aura::Window representation, as moves internal to the X11
+ // window can cause internal drag leave and enter messages.
+ void DragTranslate(const gfx::Point& root_window_location,
+ scoped_ptr<ui::OSExchangeData>* data,
+ scoped_ptr<ui::DropTargetEvent>* event,
+ aura::client::DragDropDelegate** delegate);
+
+ // Called when we need to notify the current aura::Window that we're no
+ // longer dragging over it.
+ void NotifyDragLeave();
+
+ // Converts our bitfield of actions into an Atom that represents what action
+ // we're most likely to take on drop.
+ ::Atom DragOperationToAtom(int drag_operation);
+
+ // Converts a single action atom to a drag operation.
+ int AtomToDragOperation(::Atom atom);
+
+ // During the blocking StartDragAndDrop() call, this converts the views-style
+ // |drag_operation_| bitfield into a vector of Atoms to offer to other
+ // processes.
+ std::vector< ::Atom> GetOfferedDragOperations();
+
+ // This returns a representation of the data we're offering in this
+ // drag. This is done to bypass an asynchronous roundtrip with the X11
+ // server.
+ ui::SelectionFormatMap GetFormatMap() const;
+
+ // Handling XdndPosition can be paused while waiting for more data; this is
+ // called either synchronously from OnXdndPosition, or asynchronously after
+ // we've received data requested from the other window.
+ void CompleteXdndPosition(::Window source_window,
+ const gfx::Point& screen_point);
+
+ void SendXdndEnter(::Window dest_window);
+ void SendXdndLeave(::Window dest_window);
+ void SendXdndPosition(::Window dest_window,
+ const gfx::Point& screen_point,
+ unsigned long time);
+ void SendXdndDrop(::Window dest_window);
+
+ // Sends |xev| to |xid|, optionally short circuiting the round trip to the X
+ // server.
+ void SendXClientEvent(::Window xid, XEvent* xev);
+
+ // A nested message loop that notifies this object of events through the
+ // X11WholeScreenMoveLoopDelegate interface.
+ X11WholeScreenMoveLoop move_loop_;
+
+ aura::RootWindow* root_window_;
+
+ Display* xdisplay_;
+ ::Window xwindow_;
+
+ ui::X11AtomCache atom_cache_;
+
+ // Target side information.
+ class X11DragContext;
+ scoped_ptr<X11DragContext> target_current_context_;
+
+ // The Aura window that is currently under the cursor. We need to manually
+ // keep track of this because Windows will only call our drag enter method
+ // once when the user enters the associated X Window. But inside that X
+ // Window there could be multiple aura windows, so we need to generate drag
+ // enter events for them.
+ aura::Window* target_window_;
+
+ // Because Xdnd messages don't contain the position in messages other than
+ // the XdndPosition message, we must manually keep track of the last position
+ // change.
+ gfx::Point target_window_location_;
+ gfx::Point target_window_root_location_;
+
+ // In the Xdnd protocol, we aren't supposed to send another XdndPosition
+ // message until we have received a confirming XdndStatus message.
+ std::set< ::Window> waiting_on_status_;
+
+ // If we would send an XdndPosition message while we're waiting for an
+ // XdndStatus response, we need to cache the latest details we'd send.
+ NextPositionMap next_position_message_;
+
+ // Source side information.
+ ui::OSExchangeDataProviderAuraX11 const* source_provider_;
+ ::Window source_current_window_;
+
+ bool drag_drop_in_progress_;
+
+ // The operation bitfield as requested by StartDragAndDrop.
+ int drag_operation_;
+
+ // The operation performed. Is initialized to None at the start of
+ // StartDragAndDrop(), and is set only during the asynchronous XdndFinished
+ // message.
+ int resulting_operation_;
+
+ // This window will be receiving a drop as soon as we receive an XdndStatus
+ // from it.
+ std::set< ::Window> pending_drop_;
+
+ // We offer the other window a list of possible operations,
+ // XdndActionsList. This is the requested action from the other window. This
+ // is None if we haven't sent out an XdndPosition message yet, haven't yet
+ // received an XdndStatus or if the other window has told us that there's no
+ // action that we can agree on.
+ //
+ // This is a map instead of a simple variable because of the case where we
+ // put an XdndLeave in the queue at roughly the same time that the other
+ // window responds to an XdndStatus.
+ std::map< ::Window, ::Atom> negotiated_operation_;
+
+ // We use these cursors while dragging.
+ gfx::NativeCursor grab_cursor_;
+ gfx::NativeCursor copy_grab_cursor_;
+ gfx::NativeCursor move_grab_cursor_;
+
+ static std::map< ::Window, DesktopDragDropClientAuraX11*> g_live_client_map;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
new file mode 100644
index 00000000000..840e38221b4
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
+
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/drag_source_win.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
+#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
+#include "ui/views/widget/drop_target_win.h"
+
+namespace views {
+
+DesktopDragDropClientWin::DesktopDragDropClientWin(
+ aura::RootWindow* root_window,
+ HWND window)
+ : drag_drop_in_progress_(false),
+ drag_operation_(0) {
+ drop_target_ = new DesktopDropTargetWin(root_window, window);
+}
+
+DesktopDragDropClientWin::~DesktopDragDropClientWin() {
+}
+
+int DesktopDragDropClientWin::StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::RootWindow* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ drag_drop_in_progress_ = true;
+ drag_operation_ = operation;
+
+ drag_source_ = new ui::DragSourceWin;
+ DWORD effect;
+ HRESULT result = DoDragDrop(
+ ui::OSExchangeDataProviderWin::GetIDataObject(data),
+ drag_source_,
+ ui::DragDropTypes::DragOperationToDropEffect(operation),
+ &effect);
+
+ drag_drop_in_progress_ = false;
+
+ if (result != DRAGDROP_S_DROP)
+ effect = DROPEFFECT_NONE;
+
+ return ui::DragDropTypes::DropEffectToDragOperation(effect);
+}
+
+void DesktopDragDropClientWin::DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) {
+}
+
+void DesktopDragDropClientWin::Drop(aura::Window* target,
+ const ui::LocatedEvent& event) {
+}
+
+void DesktopDragDropClientWin::DragCancel() {
+ drag_source_->CancelDrag();
+ drag_operation_ = 0;
+}
+
+bool DesktopDragDropClientWin::IsDragDropInProgress() {
+ return drag_drop_in_progress_;
+}
+
+void DesktopDragDropClientWin::OnNativeWidgetDestroying(HWND window) {
+ if (drop_target_.get()) {
+ RevokeDragDrop(window);
+ drop_target_ = NULL;
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
new file mode 100644
index 00000000000..7aa4952ab39
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_WIN_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_WIN_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/views/views_export.h"
+
+namespace ui {
+class DragSourceWin;
+class RootWindow;
+}
+
+namespace views {
+class DesktopDragDragSourceWin;
+class DesktopDropTargetWin;
+
+class VIEWS_EXPORT DesktopDragDropClientWin
+ : public aura::client::DragDropClient {
+ public:
+ DesktopDragDropClientWin(aura::RootWindow* root_window, HWND window);
+ virtual ~DesktopDragDropClientWin();
+
+ // Overridden from aura::client::DragDropClient:
+ virtual int StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::RootWindow* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) OVERRIDE;
+ virtual void Drop(aura::Window* target,
+ const ui::LocatedEvent& event) OVERRIDE;
+ virtual void DragCancel() OVERRIDE;
+ virtual bool IsDragDropInProgress() OVERRIDE;
+
+ void OnNativeWidgetDestroying(HWND window);
+
+ private:
+ bool drag_drop_in_progress_;
+
+ int drag_operation_;
+
+ scoped_refptr<ui::DragSourceWin> drag_source_;
+
+ scoped_refptr<DesktopDropTargetWin> drop_target_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_WIN_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
new file mode 100644
index 00000000000..d3a01f3c208
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -0,0 +1,139 @@
+// 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/views/widget/desktop_aura/desktop_drop_target_win.h"
+
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
+#include "ui/base/events/event.h"
+
+using aura::client::DragDropDelegate;
+using ui::OSExchangeData;
+using ui::OSExchangeDataProviderWin;
+
+namespace views {
+
+DesktopDropTargetWin::DesktopDropTargetWin(aura::RootWindow* root_window,
+ HWND window)
+ : ui::DropTargetWin(window),
+ root_window_(root_window),
+ target_window_(NULL) {
+}
+
+DesktopDropTargetWin::~DesktopDropTargetWin() {
+ if (target_window_)
+ target_window_->RemoveObserver(this);
+}
+
+DWORD DesktopDropTargetWin::OnDragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect) {
+ scoped_ptr<OSExchangeData> data;
+ scoped_ptr<ui::DropTargetEvent> event;
+ DragDropDelegate* delegate;
+ // Translate will call OnDragEntered.
+ Translate(data_object, key_state, position, effect, &data, &event, &delegate);
+ return ui::DragDropTypes::DragOperationToDropEffect(
+ ui::DragDropTypes::DRAG_NONE);
+}
+
+DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect) {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ scoped_ptr<OSExchangeData> data;
+ scoped_ptr<ui::DropTargetEvent> event;
+ DragDropDelegate* delegate;
+ Translate(data_object, key_state, position, effect, &data, &event, &delegate);
+ if (delegate)
+ drag_operation = delegate->OnDragUpdated(*event);
+ return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
+}
+
+void DesktopDropTargetWin::OnDragLeave(IDataObject* data_object) {
+ NotifyDragLeave();
+}
+
+DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect) {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ scoped_ptr<OSExchangeData> data;
+ scoped_ptr<ui::DropTargetEvent> event;
+ DragDropDelegate* delegate;
+ Translate(data_object, key_state, position, effect, &data, &event, &delegate);
+ if (delegate)
+ drag_operation = delegate->OnPerformDrop(*event);
+ if (target_window_) {
+ target_window_->RemoveObserver(this);
+ target_window_ = NULL;
+ }
+ return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
+}
+
+void DesktopDropTargetWin::OnWindowDestroyed(aura::Window* window) {
+ DCHECK(window == target_window_);
+ target_window_ = NULL;
+}
+
+void DesktopDropTargetWin::Translate(
+ IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect,
+ scoped_ptr<OSExchangeData>* data,
+ scoped_ptr<ui::DropTargetEvent>* event,
+ DragDropDelegate** delegate) {
+ gfx::Point location(position.x, position.y);
+ gfx::Point root_location = location;
+ root_window_->ConvertPointFromNativeScreen(&root_location);
+ aura::Window* target_window =
+ root_window_->GetEventHandlerForPoint(root_location);
+ bool target_window_changed = false;
+ if (target_window != target_window_) {
+ if (target_window_)
+ NotifyDragLeave();
+ target_window_ = target_window;
+ if (target_window_)
+ target_window_->AddObserver(this);
+ target_window_changed = true;
+ }
+ *delegate = NULL;
+ if (!target_window_)
+ return;
+ *delegate = aura::client::GetDragDropDelegate(target_window_);
+ if (!*delegate)
+ return;
+
+ data->reset(new OSExchangeData(new OSExchangeDataProviderWin(data_object)));
+ location = root_location;
+ aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
+ event->reset(new ui::DropTargetEvent(
+ *(data->get()),
+ location,
+ root_location,
+ ui::DragDropTypes::DropEffectToDragOperation(effect)));
+ if (target_window_changed)
+ (*delegate)->OnDragEntered(*event->get());
+}
+
+void DesktopDropTargetWin::NotifyDragLeave() {
+ if (!target_window_)
+ return;
+ DragDropDelegate* delegate =
+ aura::client::GetDragDropDelegate(target_window_);
+ if (delegate)
+ delegate->OnDragExited();
+ target_window_->RemoveObserver(this);
+ target_window_ = NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h
new file mode 100644
index 00000000000..3fde71f0a3c
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTIOP_DROP_TARGET_WIN_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTIOP_DROP_TARGET_WIN_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/dragdrop/drop_target_win.h"
+
+namespace aura {
+class RootWindow;
+namespace client {
+class DragDropDelegate;
+}
+}
+
+namespace ui {
+class DropTargetEvent;
+class OSExchangeData;
+}
+
+namespace views {
+
+// DesktopDropTargetWin takes care of managing drag and drop for
+// DesktopRootWindowHostWin. It converts Windows OLE drop messages into
+// aura::client::DragDropDelegate calls.
+class DesktopDropTargetWin : public ui::DropTargetWin,
+ public aura::WindowObserver {
+ public:
+ DesktopDropTargetWin(aura::RootWindow* root_window, HWND window);
+ virtual ~DesktopDropTargetWin();
+
+ private:
+ // ui::DropTargetWin implementation:
+ virtual DWORD OnDragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect) OVERRIDE;
+ virtual DWORD OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect) OVERRIDE;
+ virtual void OnDragLeave(IDataObject* data_object) OVERRIDE;
+ virtual DWORD OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT position,
+ DWORD effect) OVERRIDE;
+
+ // aura::WindowObserver implementation:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ // Common functionality for the ui::DropTargetWin methods to translate from
+ // COM data types to Aura ones.
+ void Translate(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect,
+ scoped_ptr<ui::OSExchangeData>* data,
+ scoped_ptr<ui::DropTargetEvent>* event,
+ aura::client::DragDropDelegate** delegate);
+
+ void NotifyDragLeave();
+
+ // The root window associated with this drop target.
+ aura::RootWindow* root_window_;
+
+ // The Aura window that is currently under the cursor. We need to manually
+ // keep track of this because Windows will only call our drag enter method
+ // once when the user enters the associated HWND. But inside that HWND there
+ // could be multiple aura windows, so we need to generate drag enter events
+ // for them.
+ aura::Window* target_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopDropTargetWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTIOP_DROP_TARGET_WIN_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
new file mode 100644
index 00000000000..54894f8dc9f
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+
+namespace views {
+
+DesktopFocusRules::DesktopFocusRules() {}
+DesktopFocusRules::~DesktopFocusRules() {}
+
+bool DesktopFocusRules::SupportsChildActivation(aura::Window* window) const {
+ // In Desktop-Aura, only children of the RootWindow are activatable.
+ return window->GetRootWindow() == window;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
new file mode 100644
index 00000000000..a7db8c2504f
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_FOCUS_RULES_H_
+#define UI_VIEWS_WIDGET_DESKTOP_FOCUS_RULES_H_
+
+#include "ui/views/corewm/base_focus_rules.h"
+
+namespace views {
+
+class DesktopFocusRules : public corewm::BaseFocusRules {
+ public:
+ DesktopFocusRules();
+ virtual ~DesktopFocusRules();
+
+ private:
+ // Overridden from corewm::BaseFocusRules:
+ virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopFocusRules);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_FOCUS_RULES_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_layout_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_layout_manager.cc
new file mode 100644
index 00000000000..f376e0b495c
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_layout_manager.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_layout_manager.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/gfx/rect.h"
+
+namespace views {
+
+DesktopLayoutManager::DesktopLayoutManager(aura::RootWindow* root_window)
+ : root_window_(root_window),
+ main_window_(NULL) {
+}
+
+DesktopLayoutManager::~DesktopLayoutManager() {}
+
+void DesktopLayoutManager::OnWindowResized() {
+ if (main_window_)
+ SetMainWindowSize();
+}
+
+void DesktopLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
+ if (!main_window_) {
+ main_window_ = child;
+
+ SetMainWindowSize();
+ }
+}
+
+void DesktopLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
+ if (main_window_ == child)
+ main_window_ = NULL;
+}
+
+void DesktopLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
+}
+
+void DesktopLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) {
+}
+
+void DesktopLayoutManager::SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) {
+ if (main_window_ != child)
+ SetChildBoundsDirect(child, requested_bounds);
+}
+
+void DesktopLayoutManager::SetMainWindowSize() {
+ gfx::Rect bounds;
+ bounds.set_size(root_window_->GetHostSize());
+ SetChildBoundsDirect(main_window_, bounds);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_layout_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_layout_manager.h
new file mode 100644
index 00000000000..c74202e2f34
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_layout_manager.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_LAYOUT_MANAGER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_LAYOUT_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/layout_manager.h"
+#include "ui/views/views_export.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+}
+
+namespace views {
+
+// A LayoutManager that by default makes the first Window added to a
+// RootWindow the full size, and will be resized as the RootWindow is resized.
+class VIEWS_EXPORT DesktopLayoutManager : public aura::LayoutManager {
+ public:
+ explicit DesktopLayoutManager(aura::RootWindow* root_window);
+ virtual ~DesktopLayoutManager();
+
+ // Overridden from aura::LayoutManager:
+ virtual void OnWindowResized() OVERRIDE;
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
+ virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE;
+ virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE;
+ virtual void OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) OVERRIDE;
+ virtual void SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) OVERRIDE;
+
+ private:
+ // Sets the size of |main_window_| to the internal bounds of |root_window_|.
+ void SetMainWindowSize();
+
+ aura::RootWindow* root_window_;
+ aura::Window* main_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopLayoutManager);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_LAYOUT_MANAGER_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
new file mode 100644
index 00000000000..a9b902dee46
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+
+namespace views {
+
+DesktopNativeCursorManager::DesktopNativeCursorManager(
+ aura::RootWindow* window,
+ scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater)
+ : root_window_(window),
+ cursor_loader_updater_(cursor_loader_updater.Pass()),
+ cursor_loader_(ui::CursorLoader::Create()) {
+ if (cursor_loader_updater_.get())
+ cursor_loader_updater_->OnCreate(root_window_, cursor_loader_.get());
+}
+
+DesktopNativeCursorManager::~DesktopNativeCursorManager() {
+}
+
+gfx::NativeCursor DesktopNativeCursorManager::GetInitializedCursor(int type) {
+ gfx::NativeCursor cursor(type);
+ cursor_loader_->SetPlatformCursor(&cursor);
+ return cursor;
+}
+
+void DesktopNativeCursorManager::SetDisplay(
+ const gfx::Display& display,
+ views::corewm::NativeCursorManagerDelegate* delegate) {
+ cursor_loader_->UnloadAll();
+ cursor_loader_->set_display(display);
+
+ if (cursor_loader_updater_.get())
+ cursor_loader_updater_->OnDisplayUpdated(display, cursor_loader_.get());
+
+ SetCursor(delegate->GetCurrentCursor(), delegate);
+}
+
+void DesktopNativeCursorManager::SetCursor(
+ gfx::NativeCursor cursor,
+ views::corewm::NativeCursorManagerDelegate* delegate) {
+ gfx::NativeCursor new_cursor = cursor;
+ cursor_loader_->SetPlatformCursor(&new_cursor);
+ delegate->CommitCursor(new_cursor);
+
+ if (delegate->GetCurrentVisibility())
+ root_window_->SetCursor(new_cursor);
+}
+
+void DesktopNativeCursorManager::SetVisibility(
+ bool visible,
+ views::corewm::NativeCursorManagerDelegate* delegate) {
+ delegate->CommitVisibility(visible);
+
+ if (visible) {
+ SetCursor(delegate->GetCurrentCursor(), delegate);
+ } else {
+ gfx::NativeCursor invisible_cursor(ui::kCursorNone);
+ cursor_loader_->SetPlatformCursor(&invisible_cursor);
+ root_window_->SetCursor(invisible_cursor);
+ }
+
+ root_window_->OnCursorVisibilityChanged(visible);
+}
+
+
+void DesktopNativeCursorManager::SetScale(
+ float scale,
+ views::corewm::NativeCursorManagerDelegate* delegate) {
+ NOTIMPLEMENTED();
+}
+
+void DesktopNativeCursorManager::SetMouseEventsEnabled(
+ bool enabled,
+ views::corewm::NativeCursorManagerDelegate* delegate) {
+ delegate->CommitMouseEventsEnabled(enabled);
+
+ // TODO(erg): In the ash version, we set the last mouse location on Env. I'm
+ // not sure this concept makes sense on the desktop.
+
+ SetVisibility(delegate->GetCurrentVisibility(), delegate);
+
+ root_window_->OnMouseEventsEnableStateChanged(enabled);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
new file mode 100644
index 00000000000..f6a800bfb9f
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/corewm/native_cursor_manager.h"
+#include "ui/views/views_export.h"
+
+namespace aura {
+class RootWindow;
+}
+
+namespace ui {
+class CursorLoader;
+}
+
+namespace views {
+class DesktopCursorLoaderUpdater;
+
+namespace corewm {
+class NativeCursorManagerDelegate;
+}
+
+// A NativeCursorManager that interacts with only one RootWindow. (Unlike the
+// one in ash, which interacts with all the RootWindows that ash knows about.)
+class VIEWS_EXPORT DesktopNativeCursorManager
+ : public views::corewm::NativeCursorManager {
+ public:
+ DesktopNativeCursorManager(
+ aura::RootWindow* window,
+ scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater);
+ virtual ~DesktopNativeCursorManager();
+
+ // Builds a cursor and sets the internal platform representation.
+ gfx::NativeCursor GetInitializedCursor(int type);
+
+ private:
+ // Overridden from views::corewm::NativeCursorManager:
+ virtual void SetDisplay(
+ const gfx::Display& display,
+ views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ virtual void SetCursor(
+ gfx::NativeCursor cursor,
+ views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ virtual void SetVisibility(
+ bool visible,
+ views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ virtual void SetScale(
+ float scale,
+ views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ virtual void SetMouseEventsEnabled(
+ bool enabled,
+ views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+
+ aura::RootWindow* root_window_;
+ scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater_;
+ scoped_ptr<ui::CursorLoader> cursor_loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopNativeCursorManager);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
+
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
new file mode 100644
index 00000000000..207e655e0e6
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -0,0 +1,884 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+
+#include "base/bind.h"
+#include "ui/aura/client/activation_client.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/stacking_client.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/root_window_host.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/hit_test.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/point_conversions.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/corewm/compound_event_filter.h"
+#include "ui/views/corewm/corewm_switches.h"
+#include "ui/views/corewm/input_method_event_filter.h"
+#include "ui/views/corewm/shadow_controller.h"
+#include "ui/views/corewm/shadow_types.h"
+#include "ui/views/corewm/tooltip_controller.h"
+#include "ui/views/corewm/visibility_controller.h"
+#include "ui/views/corewm/window_modality_controller.h"
+#include "ui/views/drag_utils.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+#include "ui/views/widget/drop_helper.h"
+#include "ui/views/widget/native_widget_aura_window_observer.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/tooltip_manager_aura.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_aura_utils.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/window_reorderer.h"
+
+DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(VIEWS_EXPORT,
+ views::DesktopNativeWidgetAura*);
+
+namespace views {
+
+DEFINE_WINDOW_PROPERTY_KEY(DesktopNativeWidgetAura*,
+ kDesktopNativeWidgetAuraKey, NULL);
+
+namespace {
+
+// This class provides functionality to create a top level fullscreen widget to
+// host a child window.
+class DesktopNativeWidgetFullscreenHandler : public aura::WindowObserver {
+ public:
+ // This function creates a full screen widget with the bounds passed in
+ // which eventually becomes the parent of the child window passed in.
+ static aura::Window* CreateParentWindow(aura::Window* child_window,
+ const gfx::Rect& bounds) {
+ // This instance will get deleted when the fullscreen widget is destroyed.
+ DesktopNativeWidgetFullscreenHandler* full_screen_handler =
+ new DesktopNativeWidgetFullscreenHandler;
+
+ child_window->SetBounds(gfx::Rect(bounds.size()));
+
+ Widget::InitParams init_params;
+ init_params.type = Widget::InitParams::TYPE_WINDOW;
+ init_params.bounds = bounds;
+ init_params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
+ init_params.layer_type = ui::LAYER_NOT_DRAWN;
+
+ // This widget instance will get deleted when the fullscreen window is
+ // destroyed.
+ full_screen_handler->full_screen_widget_ = new Widget();
+ full_screen_handler->full_screen_widget_->Init(init_params);
+
+ full_screen_handler->full_screen_widget_->SetFullscreen(true);
+ full_screen_handler->full_screen_widget_->Show();
+
+ aura::Window* native_window =
+ full_screen_handler->full_screen_widget_->GetNativeView();
+ child_window->AddObserver(full_screen_handler);
+ native_window->AddObserver(full_screen_handler);
+ return native_window;
+ }
+
+ // aura::WindowObserver overrides
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
+ window->RemoveObserver(this);
+
+ // If the widget is being destroyed by the OS then we should not try and
+ // destroy it again.
+ if (full_screen_widget_ &&
+ window == full_screen_widget_->GetNativeView()) {
+ full_screen_widget_ = NULL;
+ return;
+ }
+
+ if (full_screen_widget_) {
+ DCHECK(full_screen_widget_->GetNativeView());
+ full_screen_widget_->GetNativeView()->RemoveObserver(this);
+ // When we receive a notification that the child of the fullscreen window
+ // created above is being destroyed we go ahead and initiate the
+ // destruction of the corresponding widget.
+ full_screen_widget_->Close();
+ full_screen_widget_ = NULL;
+ }
+ delete this;
+ }
+
+ private:
+ DesktopNativeWidgetFullscreenHandler()
+ : full_screen_widget_(NULL) {}
+
+ virtual ~DesktopNativeWidgetFullscreenHandler() {}
+
+ Widget* full_screen_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetFullscreenHandler);
+};
+
+class DesktopNativeWidgetAuraStackingClient :
+ public aura::client::StackingClient {
+ public:
+ explicit DesktopNativeWidgetAuraStackingClient(aura::RootWindow* root_window)
+ : root_window_(root_window) {
+ aura::client::SetStackingClient(root_window_, this);
+ }
+ virtual ~DesktopNativeWidgetAuraStackingClient() {
+ aura::client::SetStackingClient(root_window_, NULL);
+ }
+
+ // Overridden from client::StackingClient:
+ virtual aura::Window* GetDefaultParent(aura::Window* context,
+ aura::Window* window,
+ const gfx::Rect& bounds) OVERRIDE {
+ if (window->GetProperty(aura::client::kShowStateKey) ==
+ ui::SHOW_STATE_FULLSCREEN) {
+ return DesktopNativeWidgetFullscreenHandler::CreateParentWindow(window,
+ bounds);
+ }
+ return root_window_;
+ }
+
+ private:
+ aura::RootWindow* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAuraStackingClient);
+};
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, public:
+
+DesktopNativeWidgetAura::DesktopNativeWidgetAura(
+ internal::NativeWidgetDelegate* delegate)
+ : ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
+ close_widget_factory_(this),
+ can_activate_(true),
+ desktop_root_window_host_(NULL),
+ window_(new aura::Window(this)),
+ native_widget_delegate_(delegate),
+ last_drop_operation_(ui::DragDropTypes::DRAG_NONE),
+ restore_focus_on_activate_(false),
+ cursor_(gfx::kNullCursor) {
+ window_->SetProperty(kDesktopNativeWidgetAuraKey, this);
+ aura::client::SetFocusChangeObserver(window_, this);
+ aura::client::SetActivationChangeObserver(window_, this);
+}
+
+DesktopNativeWidgetAura::~DesktopNativeWidgetAura() {
+ if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ delete native_widget_delegate_;
+ else
+ CloseNow();
+
+ stacking_client_.reset(); // Uses root_window_ at destruction.
+
+ root_window_->RemoveRootWindowObserver(this);
+ root_window_.reset(); // Uses input_method_event_filter_ at destruction.
+ input_method_event_filter_.reset();
+}
+
+// static
+DesktopNativeWidgetAura* DesktopNativeWidgetAura::ForWindow(
+ aura::Window* window) {
+ return window->GetProperty(kDesktopNativeWidgetAuraKey);
+}
+
+void DesktopNativeWidgetAura::OnHostClosed() {
+ root_window_event_filter_->RemoveHandler(input_method_event_filter_.get());
+ // This will, through a long list of callbacks, trigger |root_window_| going
+ // away. See OnWindowDestroyed()
+ delete window_;
+}
+
+void DesktopNativeWidgetAura::InstallInputMethodEventFilter(
+ aura::RootWindow* root) {
+ DCHECK(!input_method_event_filter_.get());
+
+ // CEF sets focus to the window the user clicks down on.
+ // TODO(beng): see if we can't do this some other way. CEF seems a heavy-
+ // handed way of accomplishing focus.
+ // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow.
+ root_window_event_filter_ = new corewm::CompoundEventFilter;
+ // Pass ownership of the filter to the root_window.
+ root->SetEventFilter(root_window_event_filter_);
+
+ input_method_event_filter_.reset(
+ new corewm::InputMethodEventFilter(root->GetAcceleratedWidget()));
+ input_method_event_filter_->SetInputMethodPropertyInRootWindow(root);
+ root_window_event_filter_->AddHandler(input_method_event_filter_.get());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation:
+
+void DesktopNativeWidgetAura::InitNativeWidget(
+ const Widget::InitParams& params) {
+ ownership_ = params.ownership;
+
+ window_->set_user_data(this);
+ window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
+ window_->SetTransparent(true);
+ window_->Init(params.layer_type);
+ corewm::SetShadowType(window_, corewm::SHADOW_TYPE_NONE);
+#if defined(OS_LINUX) // TODO(scottmg): http://crbug.com/180071
+ window_->Show();
+#endif
+
+ desktop_root_window_host_ = params.desktop_root_window_host ?
+ params.desktop_root_window_host :
+ DesktopRootWindowHost::Create(native_widget_delegate_,
+ this, params.bounds);
+ root_window_.reset(
+ desktop_root_window_host_->Init(window_, params));
+ root_window_->AddRootWindowObserver(this);
+
+ stacking_client_.reset(
+ new DesktopNativeWidgetAuraStackingClient(root_window_.get()));
+ drop_helper_.reset(new DropHelper(
+ static_cast<internal::RootView*>(GetWidget()->GetRootView())));
+ aura::client::SetDragDropDelegate(window_, this);
+
+ tooltip_manager_.reset(new views::TooltipManagerAura(window_, GetWidget()));
+ tooltip_controller_.reset(
+ new corewm::TooltipController(gfx::SCREEN_TYPE_NATIVE));
+ aura::client::SetTooltipClient(root_window_.get(),
+ tooltip_controller_.get());
+ root_window_->AddPreTargetHandler(tooltip_controller_.get());
+
+ if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW) {
+ visibility_controller_.reset(new views::corewm::VisibilityController);
+ aura::client::SetVisibilityClient(GetNativeView()->GetRootWindow(),
+ visibility_controller_.get());
+ views::corewm::SetChildWindowVisibilityChangesAnimated(
+ GetNativeView()->GetRootWindow());
+ }
+
+ if (params.type == Widget::InitParams::TYPE_WINDOW) {
+ window_modality_controller_.reset(
+ new views::corewm::WindowModalityController);
+ root_window_->AddPreTargetHandler(window_modality_controller_.get());
+ }
+
+ window_->Show();
+ desktop_root_window_host_->InitFocus(window_);
+
+ aura::client::SetActivationDelegate(window_, this);
+
+ shadow_controller_.reset(
+ new corewm::ShadowController(
+ aura::client::GetActivationClient(root_window_.get())));
+
+ window_reorderer_.reset(new WindowReorderer(window_,
+ GetWidget()->GetRootView()));
+}
+
+NonClientFrameView* DesktopNativeWidgetAura::CreateNonClientFrameView() {
+ return desktop_root_window_host_->CreateNonClientFrameView();
+}
+
+bool DesktopNativeWidgetAura::ShouldUseNativeFrame() const {
+ return desktop_root_window_host_->ShouldUseNativeFrame();
+}
+
+void DesktopNativeWidgetAura::FrameTypeChanged() {
+ desktop_root_window_host_->FrameTypeChanged();
+}
+
+Widget* DesktopNativeWidgetAura::GetWidget() {
+ return native_widget_delegate_->AsWidget();
+}
+
+const Widget* DesktopNativeWidgetAura::GetWidget() const {
+ return native_widget_delegate_->AsWidget();
+}
+
+gfx::NativeView DesktopNativeWidgetAura::GetNativeView() const {
+ return window_;
+}
+
+gfx::NativeWindow DesktopNativeWidgetAura::GetNativeWindow() const {
+ return window_;
+}
+
+Widget* DesktopNativeWidgetAura::GetTopLevelWidget() {
+ return GetWidget();
+}
+
+const ui::Compositor* DesktopNativeWidgetAura::GetCompositor() const {
+ return window_->layer()->GetCompositor();
+}
+
+ui::Compositor* DesktopNativeWidgetAura::GetCompositor() {
+ return window_->layer()->GetCompositor();
+}
+
+ui::Layer* DesktopNativeWidgetAura::GetLayer() {
+ return window_->layer();
+}
+
+void DesktopNativeWidgetAura::ReorderNativeViews() {
+ window_reorderer_->ReorderChildWindows();
+}
+
+void DesktopNativeWidgetAura::ViewRemoved(View* view) {
+}
+
+void DesktopNativeWidgetAura::SetNativeWindowProperty(const char* name,
+ void* value) {
+ window_->SetNativeWindowProperty(name, value);
+}
+
+void* DesktopNativeWidgetAura::GetNativeWindowProperty(const char* name) const {
+ return window_->GetNativeWindowProperty(name);
+}
+
+TooltipManager* DesktopNativeWidgetAura::GetTooltipManager() const {
+ return tooltip_manager_.get();
+}
+
+void DesktopNativeWidgetAura::SetCapture() {
+ window_->SetCapture();
+ // aura::Window doesn't implicitly update capture on the RootWindowHost, so
+ // we have to do that manually.
+ if (!desktop_root_window_host_->HasCapture())
+ window_->GetRootWindow()->SetNativeCapture();
+}
+
+void DesktopNativeWidgetAura::ReleaseCapture() {
+ window_->ReleaseCapture();
+ // aura::Window doesn't implicitly update capture on the RootWindowHost, so
+ // we have to do that manually.
+ if (desktop_root_window_host_->HasCapture())
+ window_->GetRootWindow()->ReleaseNativeCapture();
+}
+
+bool DesktopNativeWidgetAura::HasCapture() const {
+ return window_->HasCapture() && desktop_root_window_host_->HasCapture();
+}
+
+InputMethod* DesktopNativeWidgetAura::CreateInputMethod() {
+ ui::InputMethod* host = input_method_event_filter_->input_method();
+ return new InputMethodBridge(this, host, false);
+}
+
+internal::InputMethodDelegate*
+ DesktopNativeWidgetAura::GetInputMethodDelegate() {
+ return this;
+}
+
+void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) {
+ desktop_root_window_host_->CenterWindow(size);
+}
+
+void DesktopNativeWidgetAura::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* maximized) const {
+ desktop_root_window_host_->GetWindowPlacement(bounds, maximized);
+}
+
+void DesktopNativeWidgetAura::SetWindowTitle(const string16& title) {
+ desktop_root_window_host_->SetWindowTitle(title);
+}
+
+void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) {
+ desktop_root_window_host_->SetWindowIcons(window_icon, app_icon);
+}
+
+void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) {
+ // 99% of the time, we should not be asked to create a
+ // DesktopNativeWidgetAura that is modal. The case where this breaks down is
+ // when there are no browser windows and a background extension tries to
+ // display a simple alert dialog. (This case was masked because we used to
+ // have a hidden RootWindow which was the parent of these modal dialogs; they
+ // weren't displayed to the user.)
+}
+
+gfx::Rect DesktopNativeWidgetAura::GetWindowBoundsInScreen() const {
+ return desktop_root_window_host_->GetWindowBoundsInScreen();
+}
+
+gfx::Rect DesktopNativeWidgetAura::GetClientAreaBoundsInScreen() const {
+ return desktop_root_window_host_->GetClientAreaBoundsInScreen();
+}
+
+gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const {
+ return desktop_root_window_host_->GetRestoredBounds();
+}
+
+void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
+ float scale = 1;
+ aura::RootWindow* root = root_window_.get();
+ if (root) {
+ scale = gfx::Screen::GetScreenFor(root)->
+ GetDisplayNearestWindow(root).device_scale_factor();
+ }
+ gfx::Rect bounds_in_pixels(
+ gfx::ToCeiledPoint(gfx::ScalePoint(bounds.origin(), scale)),
+ gfx::ToFlooredSize(gfx::ScaleSize(bounds.size(), scale)));
+ desktop_root_window_host_->AsRootWindowHost()->SetBounds(bounds_in_pixels);
+}
+
+void DesktopNativeWidgetAura::SetSize(const gfx::Size& size) {
+ desktop_root_window_host_->SetSize(size);
+}
+
+void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) {
+}
+
+void DesktopNativeWidgetAura::StackAtTop() {
+}
+
+void DesktopNativeWidgetAura::StackBelow(gfx::NativeView native_view) {
+}
+
+void DesktopNativeWidgetAura::SetShape(gfx::NativeRegion shape) {
+ desktop_root_window_host_->SetShape(shape);
+}
+
+void DesktopNativeWidgetAura::Close() {
+ desktop_root_window_host_->Close();
+ if (window_)
+ window_->SuppressPaint();
+}
+
+void DesktopNativeWidgetAura::CloseNow() {
+ desktop_root_window_host_->CloseNow();
+}
+
+void DesktopNativeWidgetAura::Show() {
+ desktop_root_window_host_->AsRootWindowHost()->Show();
+ window_->Show();
+}
+
+void DesktopNativeWidgetAura::Hide() {
+ desktop_root_window_host_->AsRootWindowHost()->Hide();
+ if (window_)
+ window_->Hide();
+}
+
+void DesktopNativeWidgetAura::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ desktop_root_window_host_->ShowMaximizedWithBounds(restored_bounds);
+ window_->Show();
+}
+
+void DesktopNativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
+ desktop_root_window_host_->ShowWindowWithState(state);
+ window_->Show();
+}
+
+bool DesktopNativeWidgetAura::IsVisible() const {
+ return desktop_root_window_host_->IsVisible();
+}
+
+void DesktopNativeWidgetAura::Activate() {
+ desktop_root_window_host_->Activate();
+}
+
+void DesktopNativeWidgetAura::Deactivate() {
+ desktop_root_window_host_->Deactivate();
+}
+
+bool DesktopNativeWidgetAura::IsActive() const {
+ return desktop_root_window_host_->IsActive();
+}
+
+void DesktopNativeWidgetAura::SetAlwaysOnTop(bool always_on_top) {
+ desktop_root_window_host_->SetAlwaysOnTop(always_on_top);
+}
+
+void DesktopNativeWidgetAura::Maximize() {
+ desktop_root_window_host_->Maximize();
+}
+
+void DesktopNativeWidgetAura::Minimize() {
+ desktop_root_window_host_->Minimize();
+}
+
+bool DesktopNativeWidgetAura::IsMaximized() const {
+ return desktop_root_window_host_->IsMaximized();
+}
+
+bool DesktopNativeWidgetAura::IsMinimized() const {
+ return desktop_root_window_host_->IsMinimized();
+}
+
+void DesktopNativeWidgetAura::Restore() {
+ desktop_root_window_host_->Restore();
+}
+
+void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen) {
+ desktop_root_window_host_->SetFullscreen(fullscreen);
+}
+
+bool DesktopNativeWidgetAura::IsFullscreen() const {
+ return desktop_root_window_host_->IsFullscreen();
+}
+
+void DesktopNativeWidgetAura::SetOpacity(unsigned char opacity) {
+ desktop_root_window_host_->SetOpacity(opacity);
+}
+
+void DesktopNativeWidgetAura::SetUseDragFrame(bool use_drag_frame) {
+}
+
+void DesktopNativeWidgetAura::FlashFrame(bool flash_frame) {
+ desktop_root_window_host_->FlashFrame(flash_frame);
+}
+
+void DesktopNativeWidgetAura::RunShellDrag(
+ View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ views::RunShellDrag(window_, data, location, operation, source);
+}
+
+void DesktopNativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
+ if (window_)
+ window_->SchedulePaintInRect(rect);
+}
+
+void DesktopNativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
+ cursor_ = cursor;
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window_->GetRootWindow());
+ if (cursor_client)
+ cursor_client->SetCursor(cursor);
+}
+
+bool DesktopNativeWidgetAura::IsMouseEventsEnabled() const {
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window_->GetRootWindow());
+ return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
+}
+
+void DesktopNativeWidgetAura::ClearNativeFocus() {
+ desktop_root_window_host_->ClearNativeFocus();
+
+ if (ShouldActivate()) {
+ aura::client::GetFocusClient(window_)->
+ ResetFocusWithinActiveWindow(window_);
+ }
+}
+
+gfx::Rect DesktopNativeWidgetAura::GetWorkAreaBoundsInScreen() const {
+ return desktop_root_window_host_->GetWorkAreaBoundsInScreen();
+}
+
+void DesktopNativeWidgetAura::SetInactiveRenderingDisabled(bool value) {
+ if (!value) {
+ active_window_observer_.reset();
+ } else {
+ active_window_observer_.reset(
+ new NativeWidgetAuraWindowObserver(window_, native_widget_delegate_));
+ }
+ desktop_root_window_host_->SetInactiveRenderingDisabled(value);
+}
+
+Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) {
+ return desktop_root_window_host_->RunMoveLoop(drag_offset, source);
+}
+
+void DesktopNativeWidgetAura::EndMoveLoop() {
+ desktop_root_window_host_->EndMoveLoop();
+}
+
+void DesktopNativeWidgetAura::SetVisibilityChangedAnimationsEnabled(
+ bool value) {
+ desktop_root_window_host_->SetVisibilityChangedAnimationsEnabled(value);
+}
+
+ui::NativeTheme* DesktopNativeWidgetAura::GetNativeTheme() const {
+ return DesktopRootWindowHost::GetNativeTheme(window_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, aura::WindowDelegate implementation:
+
+gfx::Size DesktopNativeWidgetAura::GetMinimumSize() const {
+ return native_widget_delegate_->GetMinimumSize();
+}
+
+gfx::Size DesktopNativeWidgetAura::GetMaximumSize() const {
+ return native_widget_delegate_->GetMaximumSize();
+}
+
+void DesktopNativeWidgetAura::OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ if (old_bounds.origin() != new_bounds.origin())
+ native_widget_delegate_->OnNativeWidgetMove();
+ if (old_bounds.size() != new_bounds.size())
+ native_widget_delegate_->OnNativeWidgetSizeChanged(new_bounds.size());
+}
+
+gfx::NativeCursor DesktopNativeWidgetAura::GetCursor(const gfx::Point& point) {
+ return cursor_;
+}
+
+int DesktopNativeWidgetAura::GetNonClientComponent(
+ const gfx::Point& point) const {
+ return native_widget_delegate_->GetNonClientComponent(point);
+}
+
+bool DesktopNativeWidgetAura::ShouldDescendIntoChildForEventHandling(
+ aura::Window* child,
+ const gfx::Point& location) {
+ views::WidgetDelegate* widget_delegate = GetWidget()->widget_delegate();
+ return !widget_delegate ||
+ widget_delegate->ShouldDescendIntoChildForEventHandling(child, location);
+}
+
+bool DesktopNativeWidgetAura::CanFocus() {
+ return true;
+}
+
+void DesktopNativeWidgetAura::OnCaptureLost() {
+ native_widget_delegate_->OnMouseCaptureLost();
+}
+
+void DesktopNativeWidgetAura::OnPaint(gfx::Canvas* canvas) {
+ native_widget_delegate_->OnNativeWidgetPaint(canvas);
+}
+
+void DesktopNativeWidgetAura::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+void DesktopNativeWidgetAura::OnWindowDestroying() {
+ // DesktopRootWindowHost owns the ActivationController which ShadowController
+ // references. Make sure we destroy ShadowController early on.
+ shadow_controller_.reset();
+ // The DesktopRootWindowHost implementation sends OnNativeWidgetDestroying().
+ tooltip_manager_.reset();
+ if (tooltip_controller_.get()) {
+ root_window_->RemovePreTargetHandler(tooltip_controller_.get());
+ tooltip_controller_.reset();
+ aura::client::SetTooltipClient(root_window_.get(), NULL);
+ }
+ if (window_modality_controller_) {
+ root_window_->RemovePreTargetHandler(window_modality_controller_.get());
+ window_modality_controller_.reset();
+ }
+}
+
+void DesktopNativeWidgetAura::OnWindowDestroyed() {
+ window_ = NULL;
+ native_widget_delegate_->OnNativeWidgetDestroyed();
+ if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ delete this;
+}
+
+void DesktopNativeWidgetAura::OnWindowTargetVisibilityChanged(bool visible) {
+}
+
+bool DesktopNativeWidgetAura::HasHitTestMask() const {
+ return native_widget_delegate_->HasHitTestMask();
+}
+
+void DesktopNativeWidgetAura::GetHitTestMask(gfx::Path* mask) const {
+ native_widget_delegate_->GetHitTestMask(mask);
+}
+
+scoped_refptr<ui::Texture> DesktopNativeWidgetAura::CopyTexture() {
+ // The layer we create doesn't have an external texture, so this should never
+ // get invoked.
+ NOTREACHED();
+ return scoped_refptr<ui::Texture>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, ui::EventHandler implementation:
+
+void DesktopNativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) {
+ if (event->is_char()) {
+ // If a ui::InputMethod object is attached to the root window, character
+ // events are handled inside the object and are not passed to this function.
+ // If such object is not attached, character events might be sent (e.g. on
+ // Windows). In this case, we just skip these.
+ return;
+ }
+ // Renderer may send a key event back to us if the key event wasn't handled,
+ // and the window may be invisible by that time.
+ if (!window_->IsVisible())
+ return;
+
+ native_widget_delegate_->OnKeyEvent(event);
+ if (event->handled())
+ return;
+
+ if (GetWidget()->HasFocusManager() &&
+ !GetWidget()->GetFocusManager()->OnKeyEvent(*event))
+ event->SetHandled();
+}
+
+void DesktopNativeWidgetAura::OnMouseEvent(ui::MouseEvent* event) {
+ DCHECK(window_->IsVisible());
+ if (tooltip_manager_.get())
+ tooltip_manager_->UpdateTooltip();
+ native_widget_delegate_->OnMouseEvent(event);
+ // WARNING: we may have been deleted.
+}
+
+void DesktopNativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) {
+ if (event->type() == ui::ET_SCROLL) {
+ native_widget_delegate_->OnScrollEvent(event);
+ if (event->handled())
+ return;
+
+ // Convert unprocessed scroll events into wheel events.
+ ui::MouseWheelEvent mwe(*static_cast<ui::ScrollEvent*>(event));
+ native_widget_delegate_->OnMouseEvent(&mwe);
+ if (mwe.handled())
+ event->SetHandled();
+ } else {
+ native_widget_delegate_->OnScrollEvent(event);
+ }
+}
+
+void DesktopNativeWidgetAura::OnTouchEvent(ui::TouchEvent* event) {
+ native_widget_delegate_->OnTouchEvent(event);
+}
+
+void DesktopNativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
+ native_widget_delegate_->OnGestureEvent(event);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, aura::client::ActivationDelegate implementation:
+
+bool DesktopNativeWidgetAura::ShouldActivate() const {
+ return can_activate_ && native_widget_delegate_->CanActivate();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, aura::client::ActivationChangeObserver
+// implementation:
+
+void DesktopNativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ DCHECK(window_ == gained_active || window_ == lost_active);
+ if ((window_ == gained_active || window_ == lost_active) &&
+ IsVisible() && GetWidget()->non_client_view()) {
+ GetWidget()->non_client_view()->SchedulePaint();
+ }
+ if (gained_active == window_ && restore_focus_on_activate_) {
+ restore_focus_on_activate_ = false;
+ GetWidget()->GetFocusManager()->RestoreFocusedView();
+ } else if (lost_active == window_ && GetWidget()->HasFocusManager()) {
+ bool store_focused_view = corewm::UseFocusControllerOnDesktop();
+ if (!store_focused_view) {
+ // If we're losing focus to a window that is a top level (such as a
+ // bubble) store the focus. Such a window shares the same
+ // RootWindowHost, so that such a change won't trigger an activation
+ // change (which calls StoreFocusedView()). Without this the focused
+ // view is never told it lost focus.
+ aura::Window* focused_window =
+ aura::client::GetFocusClient(window_)->GetFocusedWindow();
+ if (focused_window && focused_window != window_) {
+ Widget* focused_widget =
+ Widget::GetWidgetForNativeWindow(focused_window);
+ store_focused_view = focused_widget && focused_widget != GetWidget() &&
+ focused_widget->is_top_level();
+ }
+ }
+ if (store_focused_view) {
+ DCHECK(!restore_focus_on_activate_);
+ restore_focus_on_activate_ = true;
+ // Pass in false so that ClearNativeFocus() isn't invoked.
+ GetWidget()->GetFocusManager()->StoreFocusedView(false);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, aura::client::FocusChangeObserver implementation:
+
+void DesktopNativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ if (window_ == gained_focus) {
+ desktop_root_window_host_->OnNativeWidgetFocus();
+ native_widget_delegate_->OnNativeFocus(lost_focus);
+
+ // If focus is moving from a descendant Window to |window_| then native
+ // activation hasn't changed. We still need to inform the InputMethod we've
+ // been focused though.
+ InputMethod* input_method = GetWidget()->GetInputMethod();
+ if (input_method)
+ input_method->OnFocus();
+ } else if (window_ == lost_focus) {
+ desktop_root_window_host_->OnNativeWidgetBlur();
+ native_widget_delegate_->OnNativeBlur(
+ aura::client::GetFocusClient(window_)->GetFocusedWindow());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, views::internal::InputMethodDelegate:
+
+void DesktopNativeWidgetAura::DispatchKeyEventPostIME(const ui::KeyEvent& key) {
+ FocusManager* focus_manager =
+ native_widget_delegate_->AsWidget()->GetFocusManager();
+ native_widget_delegate_->OnKeyEvent(const_cast<ui::KeyEvent*>(&key));
+ if (key.handled() || !focus_manager)
+ return;
+ focus_manager->OnKeyEvent(key);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, aura::WindowDragDropDelegate implementation:
+
+void DesktopNativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_.get() != NULL);
+ last_drop_operation_ = drop_helper_->OnDragOver(event.data(),
+ event.location(), event.source_operations());
+}
+
+int DesktopNativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_.get() != NULL);
+ last_drop_operation_ = drop_helper_->OnDragOver(event.data(),
+ event.location(), event.source_operations());
+ return last_drop_operation_;
+}
+
+void DesktopNativeWidgetAura::OnDragExited() {
+ DCHECK(drop_helper_.get() != NULL);
+ drop_helper_->OnDragExit();
+}
+
+int DesktopNativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_.get() != NULL);
+ return drop_helper_->OnDrop(event.data(), event.location(),
+ last_drop_operation_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, aura::RootWindowObserver implementation:
+
+void DesktopNativeWidgetAura::OnRootWindowHostCloseRequested(
+ const aura::RootWindow* root) {
+ Close();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopNativeWidgetAura, NativeWidget implementation:
+
+ui::EventHandler* DesktopNativeWidgetAura::GetEventHandler() {
+ return this;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
new file mode 100644
index 00000000000..b98e1ccc7f9
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -0,0 +1,264 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_
+
+#include "base/memory/weak_ptr.h"
+#include "ui/aura/client/activation_change_observer.h"
+#include "ui/aura/client/activation_delegate.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/aura/root_window_observer.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/views/ime/input_method_delegate.h"
+#include "ui/views/widget/native_widget_private.h"
+
+namespace aura {
+class RootWindow;
+namespace client {
+class StackingClient;
+}
+}
+
+namespace views {
+
+namespace corewm {
+class CompoundEventFilter;
+class InputMethodEventFilter;
+class ShadowController;
+class TooltipController;
+class VisibilityController;
+class WindowModalityController;
+}
+
+class DesktopRootWindowHost;
+class DropHelper;
+class NativeWidgetAuraWindowObserver;
+class TooltipManagerAura;
+class WindowReorderer;
+
+class VIEWS_EXPORT DesktopNativeWidgetAura
+ : public internal::NativeWidgetPrivate,
+ public aura::WindowDelegate,
+ public aura::client::ActivationDelegate,
+ public aura::client::ActivationChangeObserver,
+ public aura::client::FocusChangeObserver,
+ public views::internal::InputMethodDelegate,
+ public aura::client::DragDropDelegate,
+ public aura::RootWindowObserver {
+ public:
+ explicit DesktopNativeWidgetAura(internal::NativeWidgetDelegate* delegate);
+ virtual ~DesktopNativeWidgetAura();
+
+ // Maps from window to DesktopNativeWidgetAura.
+ static DesktopNativeWidgetAura* ForWindow(aura::Window* window);
+
+ // Called by our DesktopRootWindowHost after it has deleted native resources;
+ // this is the signal that we should start our shutdown.
+ void OnHostClosed();
+
+ // Installs the input method filter on |root|. This is intended to be invoked
+ // by the DesktopRootWindowHost implementation during Init().
+ void InstallInputMethodEventFilter(aura::RootWindow* root);
+ corewm::InputMethodEventFilter* input_method_event_filter() {
+ return input_method_event_filter_.get();
+ }
+ corewm::CompoundEventFilter* root_window_event_filter() {
+ return root_window_event_filter_;
+ }
+
+ // Overridden from NativeWidget:
+ virtual ui::EventHandler* GetEventHandler() OVERRIDE;
+
+ protected:
+ // Overridden from internal::NativeWidgetPrivate:
+ virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
+ virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
+ virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual const Widget* GetWidget() const OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
+ virtual Widget* GetTopLevelWidget() OVERRIDE;
+ virtual const ui::Compositor* GetCompositor() const OVERRIDE;
+ virtual ui::Compositor* GetCompositor() OVERRIDE;
+ virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
+ virtual void ViewRemoved(View* view) OVERRIDE;
+ virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
+ virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
+ virtual TooltipManager* GetTooltipManager() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual InputMethod* CreateInputMethod() OVERRIDE;
+ virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* maximized) const OVERRIDE;
+ virtual void SetWindowTitle(const string16& title) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void StackAbove(gfx::NativeView native_view) OVERRIDE;
+ virtual void StackAtTop() OVERRIDE;
+ virtual void StackBelow(gfx::NativeView native_view) OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion shape) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual void ShowWithWindowState(ui::WindowShowState state) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetUseDragFrame(bool use_drag_frame) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual bool IsMouseEventsEnabled() const OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetInactiveRenderingDisabled(bool value) OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
+
+ // Overridden from aura::WindowDelegate:
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE;
+ virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
+ virtual bool ShouldDescendIntoChildForEventHandling(
+ aura::Window* child,
+ const gfx::Point& location) OVERRIDE;
+ virtual bool CanFocus() OVERRIDE;
+ virtual void OnCaptureLost() OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void OnWindowDestroying() OVERRIDE;
+ virtual void OnWindowDestroyed() OVERRIDE;
+ virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
+ virtual bool HasHitTestMask() const OVERRIDE;
+ virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
+ virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE;
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ // Overridden from aura::client::ActivationDelegate:
+ virtual bool ShouldActivate() const OVERRIDE;
+
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE;
+
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE;
+
+ // Overridden from views::internal::InputMethodDelegate:
+ virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE;
+
+ // Overridden from aura::client::DragDropDelegate:
+ virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragExited() OVERRIDE;
+ virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
+
+ // Overridden from aura::RootWindowObserver:
+ virtual void OnRootWindowHostCloseRequested(
+ const aura::RootWindow* root) OVERRIDE;
+
+ private:
+ // See class documentation for Widget in widget.h for a note about ownership.
+ Widget::InitParams::Ownership ownership_;
+
+ // The NativeWidget owns the RootWindow. Required because the RootWindow owns
+ // its RootWindowHost, so DesktopRootWindowHost can't own it.
+ scoped_ptr<aura::RootWindow> root_window_;
+
+ // The following factory is used for calls to close the NativeWidgetAura
+ // instance.
+ base::WeakPtrFactory<DesktopNativeWidgetAura> close_widget_factory_;
+
+ scoped_ptr<NativeWidgetAuraWindowObserver> active_window_observer_;
+
+ // Can we be made active?
+ bool can_activate_;
+
+ // Ownership passed to RootWindow on Init.
+ DesktopRootWindowHost* desktop_root_window_host_;
+ aura::Window* window_;
+ internal::NativeWidgetDelegate* native_widget_delegate_;
+
+ scoped_ptr<aura::client::StackingClient> stacking_client_;
+
+ // Toplevel event filter which dispatches to other event filters.
+ corewm::CompoundEventFilter* root_window_event_filter_;
+
+ scoped_ptr<corewm::InputMethodEventFilter> input_method_event_filter_;
+
+ scoped_ptr<DropHelper> drop_helper_;
+ int last_drop_operation_;
+
+ scoped_ptr<corewm::TooltipController> tooltip_controller_;
+ scoped_ptr<TooltipManagerAura> tooltip_manager_;
+
+ scoped_ptr<views::corewm::VisibilityController> visibility_controller_;
+
+ scoped_ptr<views::corewm::WindowModalityController>
+ window_modality_controller_;
+
+ // See comments in OnLostActive().
+ bool restore_focus_on_activate_;
+
+ gfx::NativeCursor cursor_;
+
+ scoped_ptr<corewm::ShadowController> shadow_controller_;
+
+ // Reorders child windows of |window_| associated with a view based on the
+ // order of the associated views in the widget's view hierarchy.
+ scoped_ptr<WindowReorderer> window_reorderer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAura);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h
new file mode 100644
index 00000000000..afc412aad65
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
+
+#include "ui/base/ui_base_types.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura {
+class RootWindowHost;
+class Window;
+}
+
+namespace gfx {
+class ImageSkia;
+class Rect;
+}
+
+namespace ui {
+class NativeTheme;
+}
+
+namespace views {
+class DesktopNativeWidgetAura;
+namespace internal {
+class NativeWidgetDelegate;
+}
+
+class VIEWS_EXPORT DesktopRootWindowHost {
+ public:
+ virtual ~DesktopRootWindowHost() {}
+
+ static DesktopRootWindowHost* Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds);
+
+ // Return the NativeTheme to use for |window|. WARNING: |window| may be NULL.
+ static ui::NativeTheme* GetNativeTheme(aura::Window* window);
+
+ // Creates the aura resources associated with the native window we built.
+ // Caller takes ownership of returned RootWindow.
+ virtual aura::RootWindow* Init(aura::Window* content_window,
+ const Widget::InitParams& params) = 0;
+ virtual void InitFocus(aura::Window* window) = 0;
+
+ virtual void Close() = 0;
+ virtual void CloseNow() = 0;
+
+ virtual aura::RootWindowHost* AsRootWindowHost() = 0;
+
+ virtual void ShowWindowWithState(ui::WindowShowState show_state) = 0;
+ virtual void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) = 0;
+
+ virtual bool IsVisible() const = 0;
+
+ virtual void SetSize(const gfx::Size& size) = 0;
+ virtual void CenterWindow(const gfx::Size& size) = 0;
+ virtual void GetWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const = 0;
+ virtual gfx::Rect GetWindowBoundsInScreen() const = 0;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const = 0;
+ virtual gfx::Rect GetRestoredBounds() const = 0;
+
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0;
+
+ virtual void SetShape(gfx::NativeRegion native_region) = 0;
+
+ virtual void Activate() = 0;
+ virtual void Deactivate() = 0;
+ virtual bool IsActive() const = 0;
+ virtual void Maximize() = 0;
+ virtual void Minimize() = 0;
+ virtual void Restore() = 0;
+ virtual bool IsMaximized() const = 0;
+ virtual bool IsMinimized() const = 0;
+
+ virtual bool HasCapture() const = 0;
+
+ virtual void SetAlwaysOnTop(bool always_on_top) = 0;
+
+ virtual void SetWindowTitle(const string16& title) = 0;
+
+ virtual void ClearNativeFocus() = 0;
+
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) = 0;
+ virtual void EndMoveLoop() = 0;
+
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) = 0;
+
+ virtual bool ShouldUseNativeFrame() = 0;
+ virtual void FrameTypeChanged() = 0;
+ virtual NonClientFrameView* CreateNonClientFrameView() = 0;
+
+ virtual void SetFullscreen(bool fullscreen) = 0;
+ virtual bool IsFullscreen() const = 0;
+
+ virtual void SetOpacity(unsigned char opacity) = 0;
+
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) = 0;
+
+ virtual void InitModalType(ui::ModalType modal_type) = 0;
+
+ virtual void FlashFrame(bool flash_frame) = 0;
+
+ // Called when the DesktopNativeWidgetAura's aura::Window is focused and
+ // blurred.
+ virtual void OnNativeWidgetFocus() = 0;
+ virtual void OnNativeWidgetBlur() = 0;
+
+ // Paints the host window as activated depending on the bool passed in.
+ virtual void SetInactiveRenderingDisabled(bool disable_inactive) = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h
new file mode 100644
index 00000000000..f430b38c20d
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_OBSERVER_X11_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_OBSERVER_X11_H_
+
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// Allows for the observation of lower level window events.
+class VIEWS_EXPORT DesktopRootWindowHostObserverX11 {
+ public:
+ virtual ~DesktopRootWindowHostObserverX11() {}
+
+ // Called after we receive a MapNotify event (the X11 server has allocated
+ // resources for it).
+ virtual void OnWindowMapped(unsigned long xid) = 0;
+
+ // Called after we receive an UnmapNotify event (the X11 server has freed
+ // resources for it).
+ virtual void OnWindowUnmapped(unsigned long xid) = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_OBSERVER_X11_H_
+
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
new file mode 100644
index 00000000000..6b0de6a4628
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
@@ -0,0 +1,885 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
+
+#include "base/win/metro.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/cursor/cursor_loader_win.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/win/tsf_bridge.h"
+#include "ui/base/win/dpi.h"
+#include "ui/base/win/shell.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/path_win.h"
+#include "ui/native_theme/native_theme_aura.h"
+#include "ui/native_theme/native_theme_win.h"
+#include "ui/views/corewm/compound_event_filter.h"
+#include "ui/views/corewm/corewm_switches.h"
+#include "ui/views/corewm/cursor_manager.h"
+#include "ui/views/corewm/focus_controller.h"
+#include "ui/views/corewm/input_method_event_filter.h"
+#include "ui/views/corewm/window_animations.h"
+#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/widget/desktop_aura/desktop_activation_client.h"
+#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
+#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_hwnd_utils.h"
+#include "ui/views/win/fullscreen_handler.h"
+#include "ui/views/win/hwnd_message_handler.h"
+#include "ui/views/window/native_frame_view.h"
+
+namespace views {
+
+DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kContentWindowForRootWindow, NULL);
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostWin, public:
+
+DesktopRootWindowHostWin::DesktopRootWindowHostWin(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds)
+ : root_window_(NULL),
+ message_handler_(new HWNDMessageHandler(this)),
+ native_widget_delegate_(native_widget_delegate),
+ desktop_native_widget_aura_(desktop_native_widget_aura),
+ root_window_host_delegate_(NULL),
+ content_window_(NULL),
+ should_animate_window_close_(false),
+ pending_close_(false),
+ has_non_client_view_(false) {
+}
+
+DesktopRootWindowHostWin::~DesktopRootWindowHostWin() {
+ if (corewm::UseFocusControllerOnDesktop()) {
+ aura::client::SetFocusClient(root_window_, NULL);
+ aura::client::SetActivationClient(root_window_, NULL);
+ }
+}
+
+// static
+aura::Window* DesktopRootWindowHostWin::GetContentWindowForHWND(HWND hwnd) {
+ aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(hwnd);
+ return root ? root->GetProperty(kContentWindowForRootWindow) : NULL;
+}
+
+// static
+ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
+ // Use NativeThemeWin for windows shown on the desktop, those not on the
+ // desktop come from Ash and get NativeThemeAura.
+ aura::RootWindow* root = window ? window->GetRootWindow() : NULL;
+ if (root) {
+ HWND root_hwnd = root->GetAcceleratedWidget();
+ if (root_hwnd &&
+ DesktopRootWindowHostWin::GetContentWindowForHWND(root_hwnd)) {
+ return ui::NativeThemeWin::instance();
+ }
+ }
+ return ui::NativeThemeAura::instance();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostWin, DesktopRootWindowHost implementation:
+
+aura::RootWindow* DesktopRootWindowHostWin::Init(
+ aura::Window* content_window,
+ const Widget::InitParams& params) {
+ // TODO(beng): SetInitParams().
+ content_window_ = content_window;
+
+ ConfigureWindowStyles(message_handler_.get(), params,
+ GetWidget()->widget_delegate(),
+ native_widget_delegate_);
+
+ HWND parent_hwnd = NULL;
+ aura::Window* parent_window = params.parent;
+ if (parent_window)
+ parent_hwnd = parent_window->GetRootWindow()->GetAcceleratedWidget();
+
+ message_handler_->set_remove_standard_frame(params.remove_standard_frame);
+
+ has_non_client_view_ = Widget::RequiresNonClientView(params.type);
+
+ gfx::Rect pixel_bounds = ui::win::DIPToScreenRect(params.bounds);
+ message_handler_->Init(parent_hwnd, pixel_bounds);
+
+ aura::RootWindow::CreateParams rw_params(params.bounds);
+ rw_params.host = this;
+ root_window_ = new aura::RootWindow(rw_params);
+
+ // TODO(beng): We probably need to move these two calls to some function that
+ // can change depending on the native-ness of the frame. For right
+ // now in the hack-n-slash days of win-aura, we can just
+ // unilaterally turn this on.
+ root_window_->compositor()->SetHostHasTransparentBackground(true);
+ root_window_->SetTransparent(true);
+
+ root_window_->Init();
+ root_window_->AddChild(content_window_);
+
+ capture_client_.reset(new views::DesktopCaptureClient(root_window_));
+ aura::client::SetCaptureClient(root_window_, capture_client_.get());
+
+ if (corewm::UseFocusControllerOnDesktop()) {
+ corewm::FocusController* focus_controller =
+ new corewm::FocusController(new DesktopFocusRules);
+ focus_client_.reset(focus_controller);
+ aura::client::SetFocusClient(root_window_, focus_controller);
+ aura::client::SetActivationClient(root_window_, focus_controller);
+ root_window_->AddPreTargetHandler(focus_controller);
+ } else {
+ focus_client_.reset(new aura::FocusManager);
+ aura::client::SetFocusClient(root_window_, focus_client_.get());
+ activation_client_.reset(new DesktopActivationClient(root_window_));
+ }
+
+ dispatcher_client_.reset(new DesktopDispatcherClient);
+ aura::client::SetDispatcherClient(root_window_,
+ dispatcher_client_.get());
+
+ cursor_client_.reset(
+ new views::corewm::CursorManager(
+ scoped_ptr<corewm::NativeCursorManager>(
+ new views::DesktopNativeCursorManager(
+ root_window_,
+ scoped_ptr<DesktopCursorLoaderUpdater>()))));
+ aura::client::SetCursorClient(root_window_,
+ cursor_client_.get());
+
+ position_client_.reset(new DesktopScreenPositionClient());
+ aura::client::SetScreenPositionClient(root_window_,
+ position_client_.get());
+
+ desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_);
+
+ drag_drop_client_.reset(new DesktopDragDropClientWin(root_window_,
+ GetHWND()));
+ aura::client::SetDragDropClient(root_window_, drag_drop_client_.get());
+
+ focus_client_->FocusWindow(content_window_);
+ root_window_->SetProperty(kContentWindowForRootWindow, content_window_);
+
+ aura::client::SetAnimationHost(content_window_, this);
+
+ should_animate_window_close_ =
+ content_window_->type() != aura::client::WINDOW_TYPE_NORMAL &&
+ !views::corewm::WindowAnimationsDisabled(content_window_);
+
+ return root_window_;
+}
+
+void DesktopRootWindowHostWin::InitFocus(aura::Window* window) {
+ focus_client_->FocusWindow(window);
+}
+
+void DesktopRootWindowHostWin::Close() {
+ if (should_animate_window_close_) {
+ pending_close_ = true;
+ content_window_->Hide();
+ const bool is_animating =
+ content_window_->layer()->GetAnimator()->IsAnimatingProperty(
+ ui::LayerAnimationElement::VISIBILITY);
+ // Animation may not start for a number of reasons.
+ if (!is_animating)
+ message_handler_->Close();
+ // else case, OnWindowHidingAnimationCompleted does the actual Close.
+ } else {
+ message_handler_->Close();
+ }
+}
+
+void DesktopRootWindowHostWin::CloseNow() {
+ message_handler_->CloseNow();
+}
+
+aura::RootWindowHost* DesktopRootWindowHostWin::AsRootWindowHost() {
+ return this;
+}
+
+void DesktopRootWindowHostWin::ShowWindowWithState(
+ ui::WindowShowState show_state) {
+ message_handler_->ShowWindowWithState(show_state);
+}
+
+void DesktopRootWindowHostWin::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ gfx::Rect pixel_bounds = ui::win::DIPToScreenRect(restored_bounds);
+ message_handler_->ShowMaximizedWithBounds(pixel_bounds);
+}
+
+bool DesktopRootWindowHostWin::IsVisible() const {
+ return message_handler_->IsVisible();
+}
+
+void DesktopRootWindowHostWin::SetSize(const gfx::Size& size) {
+ gfx::Size size_in_pixels = ui::win::DIPToScreenSize(size);
+ message_handler_->SetSize(size_in_pixels);
+}
+
+void DesktopRootWindowHostWin::CenterWindow(const gfx::Size& size) {
+ gfx::Size size_in_pixels = ui::win::DIPToScreenSize(size);
+ message_handler_->CenterWindow(size_in_pixels);
+}
+
+void DesktopRootWindowHostWin::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ message_handler_->GetWindowPlacement(bounds, show_state);
+ *bounds = ui::win::ScreenToDIPRect(*bounds);
+}
+
+gfx::Rect DesktopRootWindowHostWin::GetWindowBoundsInScreen() const {
+ gfx::Rect pixel_bounds = message_handler_->GetWindowBoundsInScreen();
+ return ui::win::ScreenToDIPRect(pixel_bounds);
+}
+
+gfx::Rect DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() const {
+ gfx::Rect pixel_bounds = message_handler_->GetClientAreaBoundsInScreen();
+ return ui::win::ScreenToDIPRect(pixel_bounds);
+}
+
+gfx::Rect DesktopRootWindowHostWin::GetRestoredBounds() const {
+ gfx::Rect pixel_bounds = message_handler_->GetRestoredBounds();
+ return ui::win::ScreenToDIPRect(pixel_bounds);
+}
+
+gfx::Rect DesktopRootWindowHostWin::GetWorkAreaBoundsInScreen() const {
+ MONITORINFO monitor_info;
+ monitor_info.cbSize = sizeof(monitor_info);
+ GetMonitorInfo(MonitorFromWindow(message_handler_->hwnd(),
+ MONITOR_DEFAULTTONEAREST),
+ &monitor_info);
+ gfx::Rect pixel_bounds = gfx::Rect(monitor_info.rcWork);
+ return ui::win::ScreenToDIPRect(pixel_bounds);
+}
+
+void DesktopRootWindowHostWin::SetShape(gfx::NativeRegion native_region) {
+ SkPath path;
+ native_region->getBoundaryPath(&path);
+ message_handler_->SetRegion(gfx::CreateHRGNFromSkPath(path));
+}
+
+void DesktopRootWindowHostWin::Activate() {
+ message_handler_->Activate();
+}
+
+void DesktopRootWindowHostWin::Deactivate() {
+ message_handler_->Deactivate();
+}
+
+bool DesktopRootWindowHostWin::IsActive() const {
+ return message_handler_->IsActive();
+}
+
+void DesktopRootWindowHostWin::Maximize() {
+ message_handler_->Maximize();
+}
+
+void DesktopRootWindowHostWin::Minimize() {
+ message_handler_->Minimize();
+}
+
+void DesktopRootWindowHostWin::Restore() {
+ message_handler_->Restore();
+}
+
+bool DesktopRootWindowHostWin::IsMaximized() const {
+ return message_handler_->IsMaximized();
+}
+
+bool DesktopRootWindowHostWin::IsMinimized() const {
+ return message_handler_->IsMinimized();
+}
+
+bool DesktopRootWindowHostWin::HasCapture() const {
+ return message_handler_->HasCapture();
+}
+
+void DesktopRootWindowHostWin::SetAlwaysOnTop(bool always_on_top) {
+ message_handler_->SetAlwaysOnTop(always_on_top);
+}
+
+void DesktopRootWindowHostWin::SetWindowTitle(const string16& title) {
+ message_handler_->SetTitle(title);
+}
+
+void DesktopRootWindowHostWin::ClearNativeFocus() {
+ message_handler_->ClearNativeFocus();
+}
+
+Widget::MoveLoopResult DesktopRootWindowHostWin::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) {
+ return message_handler_->RunMoveLoop(drag_offset) ?
+ Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
+}
+
+void DesktopRootWindowHostWin::EndMoveLoop() {
+ message_handler_->EndMoveLoop();
+}
+
+void DesktopRootWindowHostWin::SetVisibilityChangedAnimationsEnabled(
+ bool value) {
+ message_handler_->SetVisibilityChangedAnimationsEnabled(value);
+ content_window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
+}
+
+bool DesktopRootWindowHostWin::ShouldUseNativeFrame() {
+ return ui::win::IsAeroGlassEnabled();
+}
+
+void DesktopRootWindowHostWin::FrameTypeChanged() {
+ message_handler_->FrameTypeChanged();
+}
+
+NonClientFrameView* DesktopRootWindowHostWin::CreateNonClientFrameView() {
+ return GetWidget()->ShouldUseNativeFrame() ?
+ new NativeFrameView(GetWidget()) : NULL;
+}
+
+void DesktopRootWindowHostWin::SetFullscreen(bool fullscreen) {
+ message_handler_->fullscreen_handler()->SetFullscreen(fullscreen);
+}
+
+bool DesktopRootWindowHostWin::IsFullscreen() const {
+ return message_handler_->fullscreen_handler()->fullscreen();
+}
+
+void DesktopRootWindowHostWin::SetOpacity(unsigned char opacity) {
+ message_handler_->SetOpacity(static_cast<BYTE>(opacity));
+ content_window_->layer()->SetOpacity(opacity / 255.0);
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void DesktopRootWindowHostWin::SetWindowIcons(
+ const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
+ message_handler_->SetWindowIcons(window_icon, app_icon);
+}
+
+void DesktopRootWindowHostWin::InitModalType(ui::ModalType modal_type) {
+ message_handler_->InitModalType(modal_type);
+}
+
+void DesktopRootWindowHostWin::FlashFrame(bool flash_frame) {
+ message_handler_->FlashFrame(flash_frame);
+}
+
+void DesktopRootWindowHostWin::OnNativeWidgetFocus() {
+ // HWNDMessageHandler will perform the proper updating on its own.
+}
+
+void DesktopRootWindowHostWin::OnNativeWidgetBlur() {
+}
+
+void DesktopRootWindowHostWin::SetInactiveRenderingDisabled(
+ bool disable_inactive) {
+ // Force the non-client area (most notably the title bar) to paint as either
+ // active or inactive, depending on the input.
+ SendMessage(message_handler_->hwnd(), WM_NCACTIVATE, !!disable_inactive, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostWin, RootWindowHost implementation:
+
+
+void DesktopRootWindowHostWin::SetDelegate(
+ aura::RootWindowHostDelegate* delegate) {
+ root_window_host_delegate_ = delegate;
+}
+
+aura::RootWindow* DesktopRootWindowHostWin::GetRootWindow() {
+ return root_window_;
+}
+
+gfx::AcceleratedWidget DesktopRootWindowHostWin::GetAcceleratedWidget() {
+ return message_handler_->hwnd();
+}
+
+void DesktopRootWindowHostWin::Show() {
+ message_handler_->Show();
+}
+
+void DesktopRootWindowHostWin::Hide() {
+ if (!pending_close_)
+ message_handler_->Hide();
+}
+
+void DesktopRootWindowHostWin::ToggleFullScreen() {
+}
+
+// GetBounds and SetBounds work in pixel coordinates, whereas other get/set
+// methods work in DIP.
+
+gfx::Rect DesktopRootWindowHostWin::GetBounds() const {
+ // Match the logic in HWNDMessageHandler::ClientAreaSizeChanged().
+ gfx::Rect bounds(WidgetSizeIsClientSize() ?
+ message_handler_->GetClientAreaBoundsInScreen() :
+ message_handler_->GetWindowBoundsInScreen());
+ gfx::Rect without_expansion(bounds.x() - window_expansion_.x(),
+ bounds.y() - window_expansion_.y(),
+ bounds.width() - window_expansion_.width(),
+ bounds.height() - window_expansion_.height());
+ return without_expansion;
+}
+
+void DesktopRootWindowHostWin::SetBounds(const gfx::Rect& bounds) {
+ gfx::Rect expanded(bounds.x() + window_expansion_.x(),
+ bounds.y() + window_expansion_.y(),
+ bounds.width() + window_expansion_.width(),
+ bounds.height() + window_expansion_.height());
+ message_handler_->SetBounds(expanded);
+}
+
+gfx::Insets DesktopRootWindowHostWin::GetInsets() const {
+ return gfx::Insets();
+}
+
+void DesktopRootWindowHostWin::SetInsets(const gfx::Insets& insets) {
+}
+
+gfx::Point DesktopRootWindowHostWin::GetLocationOnNativeScreen() const {
+ return GetBounds().origin();
+}
+
+void DesktopRootWindowHostWin::SetCapture() {
+ message_handler_->SetCapture();
+}
+
+void DesktopRootWindowHostWin::ReleaseCapture() {
+ message_handler_->ReleaseCapture();
+}
+
+void DesktopRootWindowHostWin::SetCursor(gfx::NativeCursor cursor) {
+ ui::CursorLoaderWin cursor_loader;
+ cursor_loader.SetPlatformCursor(&cursor);
+
+ message_handler_->SetCursor(cursor.platform());
+}
+
+bool DesktopRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(GetRootWindow());
+ if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
+ *location_return = gfx::Point(0, 0);
+ return false;
+ }
+ POINT pt = {0};
+ ::GetCursorPos(&pt);
+ *location_return =
+ gfx::Point(static_cast<int>(pt.x), static_cast<int>(pt.y));
+ return true;
+}
+
+bool DesktopRootWindowHostWin::ConfineCursorToRootWindow() {
+ return false;
+}
+
+void DesktopRootWindowHostWin::UnConfineCursor() {
+}
+
+void DesktopRootWindowHostWin::OnCursorVisibilityChanged(bool show) {
+}
+
+void DesktopRootWindowHostWin::MoveCursorTo(const gfx::Point& location) {
+ POINT cursor_location = location.ToPOINT();
+ ::ClientToScreen(GetHWND(), &cursor_location);
+ ::SetCursorPos(cursor_location.x, cursor_location.y);
+}
+
+void DesktopRootWindowHostWin::SetFocusWhenShown(bool focus_when_shown) {
+}
+
+void DesktopRootWindowHostWin::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+}
+
+void DesktopRootWindowHostWin::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+void DesktopRootWindowHostWin::PrepareForShutdown() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostWin, aura::AnimationHost implementation:
+
+void DesktopRootWindowHostWin::SetHostTransitionBounds(
+ const gfx::Rect& bounds) {
+ gfx::Rect bounds_without_expansion = GetBounds();
+ window_expansion_ = bounds;
+ SetBounds(bounds_without_expansion);
+}
+
+void DesktopRootWindowHostWin::OnWindowHidingAnimationCompleted() {
+ if (pending_close_)
+ message_handler_->Close();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostWin, HWNDMessageHandlerDelegate implementation:
+
+bool DesktopRootWindowHostWin::IsWidgetWindow() const {
+ return has_non_client_view_;
+}
+
+bool DesktopRootWindowHostWin::IsUsingCustomFrame() const {
+ return !GetWidget()->ShouldUseNativeFrame();
+}
+
+void DesktopRootWindowHostWin::SchedulePaint() {
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void DesktopRootWindowHostWin::EnableInactiveRendering() {
+ native_widget_delegate_->EnableInactiveRendering();
+}
+
+bool DesktopRootWindowHostWin::IsInactiveRenderingDisabled() {
+ return native_widget_delegate_->IsInactiveRenderingDisabled();
+}
+
+bool DesktopRootWindowHostWin::CanResize() const {
+ return GetWidget()->widget_delegate()->CanResize();
+}
+
+bool DesktopRootWindowHostWin::CanMaximize() const {
+ return GetWidget()->widget_delegate()->CanMaximize();
+}
+
+bool DesktopRootWindowHostWin::CanActivate() const {
+ return native_widget_delegate_->CanActivate();
+}
+
+bool DesktopRootWindowHostWin::WidgetSizeIsClientSize() const {
+ const Widget* widget = GetWidget()->GetTopLevelWidget();
+ return IsMaximized() || (widget && widget->ShouldUseNativeFrame());
+}
+
+bool DesktopRootWindowHostWin::CanSaveFocus() const {
+ return GetWidget()->is_top_level();
+}
+
+void DesktopRootWindowHostWin::SaveFocusOnDeactivate() {
+ GetWidget()->GetFocusManager()->StoreFocusedView(true);
+}
+
+void DesktopRootWindowHostWin::RestoreFocusOnActivate() {
+ RestoreFocusOnEnable();
+}
+
+void DesktopRootWindowHostWin::RestoreFocusOnEnable() {
+ GetWidget()->GetFocusManager()->RestoreFocusedView();
+}
+
+bool DesktopRootWindowHostWin::IsModal() const {
+ return native_widget_delegate_->IsModal();
+}
+
+int DesktopRootWindowHostWin::GetInitialShowState() const {
+ return SW_SHOWNORMAL;
+}
+
+bool DesktopRootWindowHostWin::WillProcessWorkAreaChange() const {
+ return GetWidget()->widget_delegate()->WillProcessWorkAreaChange();
+}
+
+int DesktopRootWindowHostWin::GetNonClientComponent(
+ const gfx::Point& point) const {
+ gfx::Point dip_position = ui::win::ScreenToDIPPoint(point);
+ return native_widget_delegate_->GetNonClientComponent(dip_position);
+}
+
+void DesktopRootWindowHostWin::GetWindowMask(const gfx::Size& size,
+ gfx::Path* path) {
+ if (GetWidget()->non_client_view())
+ GetWidget()->non_client_view()->GetWindowMask(size, path);
+}
+
+bool DesktopRootWindowHostWin::GetClientAreaInsets(gfx::Insets* insets) const {
+ return false;
+}
+
+void DesktopRootWindowHostWin::GetMinMaxSize(gfx::Size* min_size,
+ gfx::Size* max_size) const {
+ *min_size = native_widget_delegate_->GetMinimumSize();
+ *max_size = native_widget_delegate_->GetMaximumSize();
+}
+
+gfx::Size DesktopRootWindowHostWin::GetRootViewSize() const {
+ return GetWidget()->GetRootView()->size();
+}
+
+void DesktopRootWindowHostWin::ResetWindowControls() {
+ GetWidget()->non_client_view()->ResetWindowControls();
+}
+
+void DesktopRootWindowHostWin::PaintLayeredWindow(gfx::Canvas* canvas) {
+ GetWidget()->GetRootView()->Paint(canvas);
+}
+
+gfx::NativeViewAccessible DesktopRootWindowHostWin::GetNativeViewAccessible() {
+ return GetWidget()->GetRootView()->GetNativeViewAccessible();
+}
+
+InputMethod* DesktopRootWindowHostWin::GetInputMethod() {
+ return GetWidget()->GetInputMethodDirect();
+}
+
+bool DesktopRootWindowHostWin::ShouldHandleSystemCommands() const {
+ return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
+}
+
+void DesktopRootWindowHostWin::HandleAppDeactivated() {
+ native_widget_delegate_->EnableInactiveRendering();
+}
+
+void DesktopRootWindowHostWin::HandleActivationChanged(bool active) {
+ if (active)
+ root_window_host_delegate_->OnHostActivated();
+ native_widget_delegate_->OnNativeWidgetActivationChanged(active);
+ // If we're not active we need to deactivate the corresponding aura::Window.
+ // This way if a child widget is active it gets correctly deactivated (child
+ // widgets don't get native desktop activation changes, only aura activation
+ // changes).
+ if (!active) {
+ aura::client::ActivationClient* activation_client =
+ aura::client::GetActivationClient(root_window_);
+ if (activation_client) {
+ aura::Window* active_window = activation_client->GetActiveWindow();
+ if (active_window)
+ activation_client->DeactivateWindow(active_window);
+ }
+ }
+}
+
+bool DesktopRootWindowHostWin::HandleAppCommand(short command) {
+ // We treat APPCOMMAND ids as an extension of our command namespace, and just
+ // let the delegate figure out what to do...
+ return GetWidget()->widget_delegate() &&
+ GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
+}
+
+void DesktopRootWindowHostWin::HandleCancelMode() {
+ root_window_host_delegate_->OnHostCancelMode();
+}
+
+void DesktopRootWindowHostWin::HandleCaptureLost() {
+ root_window_host_delegate_->OnHostLostWindowCapture();
+ native_widget_delegate_->OnMouseCaptureLost();
+}
+
+void DesktopRootWindowHostWin::HandleClose() {
+ GetWidget()->Close();
+}
+
+bool DesktopRootWindowHostWin::HandleCommand(int command) {
+ return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
+}
+
+void DesktopRootWindowHostWin::HandleAccelerator(
+ const ui::Accelerator& accelerator) {
+ GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
+}
+
+void DesktopRootWindowHostWin::HandleCreate() {
+ // TODO(beng): moar
+ NOTIMPLEMENTED();
+
+ native_widget_delegate_->OnNativeWidgetCreated(true);
+
+ // 1. Window property association
+ // 2. MouseWheel.
+}
+
+void DesktopRootWindowHostWin::HandleDestroying() {
+ drag_drop_client_->OnNativeWidgetDestroying(GetHWND());
+ native_widget_delegate_->OnNativeWidgetDestroying();
+}
+
+void DesktopRootWindowHostWin::HandleDestroyed() {
+ desktop_native_widget_aura_->OnHostClosed();
+}
+
+bool DesktopRootWindowHostWin::HandleInitialFocus() {
+ return GetWidget()->SetInitialFocus();
+}
+
+void DesktopRootWindowHostWin::HandleDisplayChange() {
+ GetWidget()->widget_delegate()->OnDisplayChanged();
+}
+
+void DesktopRootWindowHostWin::HandleBeginWMSizeMove() {
+ native_widget_delegate_->OnNativeWidgetBeginUserBoundsChange();
+}
+
+void DesktopRootWindowHostWin::HandleEndWMSizeMove() {
+ native_widget_delegate_->OnNativeWidgetEndUserBoundsChange();
+}
+
+void DesktopRootWindowHostWin::HandleMove() {
+ native_widget_delegate_->OnNativeWidgetMove();
+ if (root_window_host_delegate_)
+ root_window_host_delegate_->OnHostMoved(GetBounds().origin());
+}
+
+void DesktopRootWindowHostWin::HandleWorkAreaChanged() {
+ GetWidget()->widget_delegate()->OnWorkAreaChanged();
+}
+
+void DesktopRootWindowHostWin::HandleVisibilityChanged(bool visible) {
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
+}
+
+void DesktopRootWindowHostWin::HandleClientSizeChanged(
+ const gfx::Size& new_size) {
+ gfx::Size without_expansion(new_size.width() - window_expansion_.width(),
+ new_size.height() - window_expansion_.height());
+ if (root_window_host_delegate_)
+ root_window_host_delegate_->OnHostResized(new_size);
+ // TODO(beng): replace with a layout manager??
+ gfx::Size dip_size = ui::win::ScreenToDIPSize(without_expansion);
+ content_window_->SetBounds(gfx::Rect(dip_size));
+ native_widget_delegate_->OnNativeWidgetSizeChanged(dip_size);
+}
+
+void DesktopRootWindowHostWin::HandleFrameChanged() {
+ // Replace the frame and layout the contents.
+ GetWidget()->non_client_view()->UpdateFrame(true);
+}
+
+void DesktopRootWindowHostWin::HandleNativeFocus(HWND last_focused_window) {
+ // TODO(beng): inform the native_widget_delegate_.
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->OnFocus();
+}
+
+void DesktopRootWindowHostWin::HandleNativeBlur(HWND focused_window) {
+ // TODO(beng): inform the native_widget_delegate_.
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->OnBlur();
+}
+
+bool DesktopRootWindowHostWin::HandleMouseEvent(const ui::MouseEvent& event) {
+ if (base::win::IsTSFAwareRequired() && event.IsAnyButton())
+ ui::TSFBridge::GetInstance()->CancelComposition();
+ return root_window_host_delegate_->OnHostMouseEvent(
+ const_cast<ui::MouseEvent*>(&event));
+}
+
+bool DesktopRootWindowHostWin::HandleKeyEvent(const ui::KeyEvent& event) {
+ return false;
+}
+
+bool DesktopRootWindowHostWin::HandleUntranslatedKeyEvent(
+ const ui::KeyEvent& event) {
+ scoped_ptr<ui::KeyEvent> duplicate_event(event.Copy());
+ return static_cast<aura::RootWindowHostDelegate*>(root_window_)->
+ OnHostKeyEvent(duplicate_event.get());
+}
+
+bool DesktopRootWindowHostWin::HandleTouchEvent(
+ const ui::TouchEvent& event) {
+ return root_window_host_delegate_->OnHostTouchEvent(
+ const_cast<ui::TouchEvent*>(&event));
+}
+
+bool DesktopRootWindowHostWin::HandleIMEMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) {
+ MSG msg = {};
+ msg.hwnd = GetHWND();
+ msg.message = message;
+ msg.wParam = w_param;
+ msg.lParam = l_param;
+ return desktop_native_widget_aura_->input_method_event_filter()->
+ input_method()->OnUntranslatedIMEMessage(msg, result);
+}
+
+void DesktopRootWindowHostWin::HandleInputLanguageChange(
+ DWORD character_set,
+ HKL input_language_id) {
+ desktop_native_widget_aura_->input_method_event_filter()->
+ input_method()->OnInputLocaleChanged();
+}
+
+bool DesktopRootWindowHostWin::HandlePaintAccelerated(
+ const gfx::Rect& invalid_rect) {
+ return native_widget_delegate_->OnNativeWidgetPaintAccelerated(invalid_rect);
+}
+
+void DesktopRootWindowHostWin::HandlePaint(gfx::Canvas* canvas) {
+ root_window_host_delegate_->OnHostPaint(gfx::Rect());
+}
+
+bool DesktopRootWindowHostWin::HandleTooltipNotify(int w_param,
+ NMHDR* l_param,
+ LRESULT* l_result) {
+ return false;
+}
+
+void DesktopRootWindowHostWin::HandleTooltipMouseMove(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+}
+
+bool DesktopRootWindowHostWin::PreHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) {
+ return false;
+}
+
+void DesktopRootWindowHostWin::PostHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostWin, private:
+
+Widget* DesktopRootWindowHostWin::GetWidget() {
+ return native_widget_delegate_->AsWidget();
+}
+
+const Widget* DesktopRootWindowHostWin::GetWidget() const {
+ return native_widget_delegate_->AsWidget();
+}
+
+HWND DesktopRootWindowHostWin::GetHWND() const {
+ return message_handler_->hwnd();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHost, public:
+
+// static
+DesktopRootWindowHost* DesktopRootWindowHost::Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds) {
+ return new DesktopRootWindowHostWin(native_widget_delegate,
+ desktop_native_widget_aura,
+ initial_bounds);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
new file mode 100644
index 00000000000..13f043d81c2
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_WIN_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_WIN_H_
+
+#include "ui/aura/client/animation_host.h"
+#include "ui/aura/root_window_host.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+#include "ui/views/win/hwnd_message_handler_delegate.h"
+
+namespace aura {
+namespace client {
+class FocusClient;
+class ScreenPositionClient;
+}
+}
+
+namespace views {
+class DesktopActivationClient;
+class DesktopCaptureClient;
+class DesktopCursorClient;
+class DesktopDispatcherClient;
+class DesktopDragDropClientWin;
+class HWNDMessageHandler;
+
+namespace corewm {
+class CursorManager;
+}
+
+class VIEWS_EXPORT DesktopRootWindowHostWin
+ : public DesktopRootWindowHost,
+ public aura::client::AnimationHost,
+ public aura::RootWindowHost,
+ public HWNDMessageHandlerDelegate {
+ public:
+ DesktopRootWindowHostWin(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds);
+ virtual ~DesktopRootWindowHostWin();
+
+ // A way of converting an HWND into a content window.
+ static aura::Window* GetContentWindowForHWND(HWND hwnd);
+
+ protected:
+ // Overridden from DesktopRootWindowHost:
+ virtual aura::RootWindow* Init(aura::Window* content_window,
+ const Widget::InitParams& params) OVERRIDE;
+ virtual void InitFocus(aura::Window* window) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual aura::RootWindowHost* AsRootWindowHost() OVERRIDE;
+ virtual void ShowWindowWithState(ui::WindowShowState show_state) OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion native_region) OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual void SetWindowTitle(const string16& title) OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual bool ShouldUseNativeFrame() OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void OnNativeWidgetFocus() OVERRIDE;
+ virtual void OnNativeWidgetBlur() OVERRIDE;
+ virtual void SetInactiveRenderingDisabled(bool disable_inactive) OVERRIDE;
+
+ // Overridden from aura::RootWindowHost:
+ virtual void SetDelegate(aura::RootWindowHostDelegate* delegate) OVERRIDE;
+ virtual aura::RootWindow* GetRootWindow() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ToggleFullScreen() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Insets GetInsets() const OVERRIDE;
+ virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
+ virtual bool ConfineCursorToRootWindow() OVERRIDE;
+ virtual void UnConfineCursor() OVERRIDE;
+ virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
+ virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
+ virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void PrepareForShutdown() OVERRIDE;
+
+ // Overridden from aura::client::AnimationHost
+ virtual void SetHostTransitionBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void OnWindowHidingAnimationCompleted() OVERRIDE;
+
+ // Overridden from HWNDMessageHandlerDelegate:
+ virtual bool IsWidgetWindow() const OVERRIDE;
+ virtual bool IsUsingCustomFrame() const OVERRIDE;
+ virtual void SchedulePaint() OVERRIDE;
+ virtual void EnableInactiveRendering() OVERRIDE;
+ virtual bool IsInactiveRenderingDisabled() OVERRIDE;
+ virtual bool CanResize() const OVERRIDE;
+ virtual bool CanMaximize() const OVERRIDE;
+ virtual bool CanActivate() const OVERRIDE;
+ virtual bool WidgetSizeIsClientSize() const OVERRIDE;
+ virtual bool CanSaveFocus() const OVERRIDE;
+ virtual void SaveFocusOnDeactivate() OVERRIDE;
+ virtual void RestoreFocusOnActivate() OVERRIDE;
+ virtual void RestoreFocusOnEnable() OVERRIDE;
+ virtual bool IsModal() const OVERRIDE;
+ virtual int GetInitialShowState() const OVERRIDE;
+ virtual bool WillProcessWorkAreaChange() const OVERRIDE;
+ virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
+ virtual void GetWindowMask(const gfx::Size& size, gfx::Path* path) OVERRIDE;
+ virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
+ virtual void GetMinMaxSize(gfx::Size* min_size,
+ gfx::Size* max_size) const OVERRIDE;
+ virtual gfx::Size GetRootViewSize() const OVERRIDE;
+ virtual void ResetWindowControls() OVERRIDE;
+ virtual void PaintLayeredWindow(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual bool ShouldHandleSystemCommands() const OVERRIDE;
+ virtual InputMethod* GetInputMethod() OVERRIDE;
+ virtual void HandleAppDeactivated() OVERRIDE;
+ virtual void HandleActivationChanged(bool active) OVERRIDE;
+ virtual bool HandleAppCommand(short command) OVERRIDE;
+ virtual void HandleCancelMode() OVERRIDE;
+ virtual void HandleCaptureLost() OVERRIDE;
+ virtual void HandleClose() OVERRIDE;
+ virtual bool HandleCommand(int command) OVERRIDE;
+ virtual void HandleAccelerator(const ui::Accelerator& accelerator) OVERRIDE;
+ virtual void HandleCreate() OVERRIDE;
+ virtual void HandleDestroying() OVERRIDE;
+ virtual void HandleDestroyed() OVERRIDE;
+ virtual bool HandleInitialFocus() OVERRIDE;
+ virtual void HandleDisplayChange() OVERRIDE;
+ virtual void HandleBeginWMSizeMove() OVERRIDE;
+ virtual void HandleEndWMSizeMove() OVERRIDE;
+ virtual void HandleMove() OVERRIDE;
+ virtual void HandleWorkAreaChanged() OVERRIDE;
+ virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
+ virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
+ virtual void HandleFrameChanged() OVERRIDE;
+ virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE;
+ virtual void HandleNativeBlur(HWND focused_window) OVERRIDE;
+ virtual bool HandleMouseEvent(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool HandleKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual bool HandleUntranslatedKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual bool HandleTouchEvent(const ui::TouchEvent& event) OVERRIDE;
+ virtual bool HandleIMEMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) OVERRIDE;
+ virtual void HandleInputLanguageChange(DWORD character_set,
+ HKL input_language_id) OVERRIDE;
+ virtual bool HandlePaintAccelerated(const gfx::Rect& invalid_rect) OVERRIDE;
+ virtual void HandlePaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual bool HandleTooltipNotify(int w_param,
+ NMHDR* l_param,
+ LRESULT* l_result) OVERRIDE;
+ virtual void HandleTooltipMouseMove(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+ virtual bool PreHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) OVERRIDE;
+ virtual void PostHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+
+ Widget* GetWidget();
+ const Widget* GetWidget() const;
+ HWND GetHWND() const;
+
+ private:
+ // We are owned by the RootWindow, but we have to have a back pointer to it.
+ aura::RootWindow* root_window_;
+
+ scoped_ptr<HWNDMessageHandler> message_handler_;
+ scoped_ptr<DesktopCaptureClient> capture_client_;
+ scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
+ scoped_ptr<aura::client::FocusClient> focus_client_;
+ // Depends on focus_manager_.
+ scoped_ptr<DesktopActivationClient> activation_client_;
+
+ // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
+ // instead of providing this route back to Widget.
+ internal::NativeWidgetDelegate* native_widget_delegate_;
+
+ DesktopNativeWidgetAura* desktop_native_widget_aura_;
+
+ aura::RootWindowHostDelegate* root_window_host_delegate_;
+ aura::Window* content_window_;
+
+ // In some cases, we set a screen position client on |root_window_|. If we
+ // do, we're responsible for the lifetime.
+ scoped_ptr<aura::client::ScreenPositionClient> position_client_;
+
+ // Controls visibility of the cursor.
+ scoped_ptr<views::corewm::CursorManager> cursor_client_;
+
+ scoped_ptr<DesktopDragDropClientWin> drag_drop_client_;
+
+ // Extra size added to the host window. Typically, the window size matches
+ // the contained content, however, when performing a translating or scaling
+ // animation the window has to be enlarged so that the content is not
+ // clipped.
+ gfx::Rect window_expansion_;
+
+ // Whether the window close should be converted to a hide, and then actually
+ // closed on the completion of the hide animation. This is cached because
+ // the property is set on the contained window which has a shorter lifetime.
+ bool should_animate_window_close_;
+
+ // When Close()d and animations are being applied to this window, the close
+ // of the window needs to be deferred to when the close animation is
+ // completed. This variable indicates that a Close was converted to a Hide,
+ // so that when the Hide is completed the host window should be closed.
+ bool pending_close_;
+
+ // True if the widget is going to have a non_client_view. We cache this value
+ // rather than asking the Widget for the non_client_view so that we know at
+ // Init time, before the Widget has created the NonClientView.
+ bool has_non_client_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopRootWindowHostWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_WIN_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
new file mode 100644
index 00000000000..67610684875
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
@@ -0,0 +1,1351 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+
+#include <X11/extensions/shape.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/Xatom.h>
+#include <X11/Xregion.h>
+#include <X11/Xutil.h>
+
+#include "base/message_loop/message_pump_aurax11.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/client/user_action_client.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
+#include "ui/base/events/event_utils.h"
+#include "ui/base/touch/touch_factory_x11.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/path_x11.h"
+#include "ui/linux_ui/linux_ui.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/corewm/compound_event_filter.h"
+#include "ui/views/corewm/corewm_switches.h"
+#include "ui/views/corewm/cursor_manager.h"
+#include "ui/views/corewm/focus_controller.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/widget/desktop_aura/desktop_activation_client.h"
+#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h"
+#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
+#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
+#include "ui/views/widget/desktop_aura/desktop_layout_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
+#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
+#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
+#include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
+
+namespace views {
+
+DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture =
+ NULL;
+std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL;
+
+DEFINE_WINDOW_PROPERTY_KEY(
+ aura::Window*, kViewsWindowForRootWindow, NULL);
+
+DEFINE_WINDOW_PROPERTY_KEY(
+ DesktopRootWindowHostX11*, kHostForRootWindow, NULL);
+
+namespace {
+
+// Standard Linux mouse buttons for going back and forward.
+const int kBackMouseButton = 8;
+const int kForwardMouseButton = 9;
+
+// Constants that are part of EWMH.
+const int k_NET_WM_STATE_ADD = 1;
+const int k_NET_WM_STATE_REMOVE = 0;
+
+const char* kAtomsToCache[] = {
+ "WM_DELETE_WINDOW",
+ "WM_PROTOCOLS",
+ "WM_S0",
+ "_NET_WM_PID",
+ "_NET_WM_PING",
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_FULLSCREEN",
+ "_NET_WM_STATE_HIDDEN",
+ "_NET_WM_STATE_MAXIMIZED_HORZ",
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_STATE_SKIP_TASKBAR",
+ "_NET_WM_WINDOW_OPACITY",
+ "_NET_WM_WINDOW_TYPE",
+ "_NET_WM_WINDOW_TYPE_MENU",
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "_NET_WM_WINDOW_TYPE_TOOLTIP",
+ "XdndActionAsk",
+ "XdndActionCopy"
+ "XdndActionLink",
+ "XdndActionList",
+ "XdndActionMove",
+ "XdndActionPrivate",
+ "XdndAware",
+ "XdndDrop",
+ "XdndEnter",
+ "XdndFinished",
+ "XdndLeave",
+ "XdndPosition",
+ "XdndProxy", // Proxy windows?
+ "XdndSelection",
+ "XdndStatus",
+ "XdndTypeList",
+ NULL
+};
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostX11, public:
+
+DesktopRootWindowHostX11::DesktopRootWindowHostX11(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds)
+ : close_widget_factory_(this),
+ xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
+ xwindow_(0),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ atom_cache_(xdisplay_, kAtomsToCache),
+ window_mapped_(false),
+ focus_when_shown_(false),
+ current_cursor_(ui::kCursorNull),
+ native_widget_delegate_(native_widget_delegate),
+ desktop_native_widget_aura_(desktop_native_widget_aura) {
+}
+
+DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
+ root_window_->ClearProperty(kHostForRootWindow);
+ if (corewm::UseFocusControllerOnDesktop()) {
+ aura::client::SetFocusClient(root_window_, NULL);
+ aura::client::SetActivationClient(root_window_, NULL);
+ }
+}
+
+// static
+aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) {
+ aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
+ return root ? root->GetProperty(kViewsWindowForRootWindow) : NULL;
+}
+
+// static
+DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) {
+ aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
+ return root ? root->GetProperty(kHostForRootWindow) : NULL;
+}
+
+// static
+std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() {
+ std::vector<aura::Window*> windows(open_windows().size());
+ std::transform(open_windows().begin(),
+ open_windows().end(),
+ windows.begin(),
+ GetContentWindowForXID);
+ return windows;
+}
+
+void DesktopRootWindowHostX11::HandleNativeWidgetActivationChanged(
+ bool active) {
+ if (active)
+ root_window_host_delegate_->OnHostActivated();
+ native_widget_delegate_->OnNativeWidgetActivationChanged(active);
+ // If we're not active we need to deactivate the corresponding aura::Window.
+ // This way if a child widget is active it gets correctly deactivated (child
+ // widgets don't get native desktop activation changes, only aura activation
+ // changes).
+ if (!active) {
+ aura::client::ActivationClient* activation_client =
+ aura::client::GetActivationClient(root_window_);
+ if (activation_client) {
+ aura::Window* active_window = activation_client->GetActiveWindow();
+ if (active_window)
+ activation_client->DeactivateWindow(active_window);
+ }
+ }
+
+ native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
+}
+
+void DesktopRootWindowHostX11::AddObserver(
+ views::DesktopRootWindowHostObserverX11* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void DesktopRootWindowHostX11::RemoveObserver(
+ views::DesktopRootWindowHostObserverX11* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void DesktopRootWindowHostX11::CleanUpWindowList() {
+ delete open_windows_;
+ open_windows_ = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
+
+aura::RootWindow* DesktopRootWindowHostX11::Init(
+ aura::Window* content_window,
+ const Widget::InitParams& params) {
+ content_window_ = content_window;
+
+ // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
+ // whether we should be proxying requests to another DRWHL.
+
+ // In some situations, views tries to make a zero sized window, and that
+ // makes us crash. Make sure we have valid sizes.
+ Widget::InitParams sanitized_params = params;
+ if (sanitized_params.bounds.width() == 0)
+ sanitized_params.bounds.set_width(100);
+ if (sanitized_params.bounds.height() == 0)
+ sanitized_params.bounds.set_height(100);
+
+ InitX11Window(sanitized_params);
+ return InitRootWindow(sanitized_params);
+}
+
+void DesktopRootWindowHostX11::InitFocus(aura::Window* window) {
+}
+
+void DesktopRootWindowHostX11::Close() {
+ // TODO(erg): Might need to do additional hiding tasks here.
+
+ if (!close_widget_factory_.HasWeakPtrs()) {
+ // And we delay the close so that if we are called from an ATL callback,
+ // we don't destroy the window before the callback returned (as the caller
+ // may delete ourselves on destroy and the ATL callback would still
+ // dereference us when the callback returns).
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&DesktopRootWindowHostX11::CloseNow,
+ close_widget_factory_.GetWeakPtr()));
+ }
+}
+
+void DesktopRootWindowHostX11::CloseNow() {
+ if (xwindow_ == None)
+ return;
+
+ native_widget_delegate_->OnNativeWidgetDestroying();
+
+ // Remove the event listeners we've installed. We need to remove these
+ // because otherwise we get assert during ~RootWindow().
+ desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
+ x11_window_event_filter_.get());
+
+ open_windows().remove(xwindow_);
+ // Actually free our native resources.
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_);
+ XDestroyWindow(xdisplay_, xwindow_);
+ xwindow_ = None;
+
+ desktop_native_widget_aura_->OnHostClosed();
+}
+
+aura::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() {
+ return this;
+}
+
+void DesktopRootWindowHostX11::ShowWindowWithState(
+ ui::WindowShowState show_state) {
+ if (show_state != ui::SHOW_STATE_DEFAULT &&
+ show_state != ui::SHOW_STATE_NORMAL) {
+ // Only forwarding to Show().
+ NOTIMPLEMENTED();
+ }
+
+ Show();
+}
+
+void DesktopRootWindowHostX11::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ restored_bounds_ = restored_bounds;
+ Maximize();
+ Show();
+}
+
+bool DesktopRootWindowHostX11::IsVisible() const {
+ return window_mapped_;
+}
+
+void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) {
+ // TODO(erg):
+ NOTIMPLEMENTED();
+}
+
+void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
+ gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
+
+ // If |window_|'s transient parent bounds are big enough to contain |size|,
+ // use them instead.
+ if (content_window_->transient_parent()) {
+ gfx::Rect transient_parent_rect =
+ content_window_->transient_parent()->GetBoundsInScreen();
+ if (transient_parent_rect.height() >= size.height() &&
+ transient_parent_rect.width() >= size.width()) {
+ parent_bounds = transient_parent_rect;
+ }
+ }
+
+ gfx::Rect window_bounds(
+ parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
+ parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
+ size.width(),
+ size.height());
+ // Don't size the window bigger than the parent, otherwise the user may not be
+ // able to close or move it.
+ window_bounds.AdjustToFit(parent_bounds);
+
+ SetBounds(window_bounds);
+}
+
+void DesktopRootWindowHostX11::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ *bounds = bounds_;
+
+ // TODO(erg): This needs a better implementation. For now, we're just pass
+ // back the normal state until we keep track of this.
+ *show_state = ui::SHOW_STATE_NORMAL;
+}
+
+gfx::Rect DesktopRootWindowHostX11::GetWindowBoundsInScreen() const {
+ return bounds_;
+}
+
+gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const {
+ // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
+ // needed for View::ConvertPointToScreen() to work
+ // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
+ // asks windows what it thinks the client rect is.
+ //
+ // Attempts to calculate the rect by asking the NonClientFrameView what it
+ // thought its GetBoundsForClientView() were broke combobox drop down
+ // placement.
+ return bounds_;
+}
+
+gfx::Rect DesktopRootWindowHostX11::GetRestoredBounds() const {
+ // We can't reliably track the restored bounds of a window, but we can get
+ // the 90% case down. When *chrome* is the process that requests maximizing
+ // or restoring bounds, we can record the current bounds before we request
+ // maximization, and clear it when we detect a state change.
+ if (!restored_bounds_.IsEmpty())
+ return restored_bounds_;
+
+ return GetWindowBoundsInScreen();
+}
+
+gfx::Rect DesktopRootWindowHostX11::GetWorkAreaBoundsInScreen() const {
+ std::vector<int> value;
+ if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
+ value.size() >= 4) {
+ return gfx::Rect(value[0], value[1], value[2], value[3]);
+ }
+
+ // Fetch the geometry of the root window.
+ Window root;
+ int x, y;
+ unsigned int width, height;
+ unsigned int border_width, depth;
+ if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
+ &width, &height, &border_width, &depth)) {
+ NOTIMPLEMENTED();
+ return gfx::Rect(0, 0, 10, 10);
+ }
+
+ return gfx::Rect(x, y, width, height);
+}
+
+void DesktopRootWindowHostX11::SetShape(gfx::NativeRegion native_region) {
+ SkPath path;
+ native_region->getBoundaryPath(&path);
+ Region region = gfx::CreateRegionFromSkPath(path);
+ XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0, region, false);
+ XDestroyRegion(region);
+}
+
+void DesktopRootWindowHostX11::Activate() {
+ X11DesktopHandler::get()->ActivateWindow(xwindow_);
+}
+
+void DesktopRootWindowHostX11::Deactivate() {
+ // Deactivating a window means activating nothing.
+ X11DesktopHandler::get()->ActivateWindow(None);
+}
+
+bool DesktopRootWindowHostX11::IsActive() const {
+ return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
+}
+
+void DesktopRootWindowHostX11::Maximize() {
+ // When we're the process requesting the maximizing, we can accurately keep
+ // track of our restored bounds instead of relying on the heuristics that are
+ // in the PropertyNotify and ConfigureNotify handlers.
+ restored_bounds_ = bounds_;
+
+ SetWMSpecState(true,
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
+}
+
+void DesktopRootWindowHostX11::Minimize() {
+ XIconifyWindow(xdisplay_, xwindow_, 0);
+}
+
+void DesktopRootWindowHostX11::Restore() {
+ SetWMSpecState(false,
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
+}
+
+bool DesktopRootWindowHostX11::IsMaximized() const {
+ return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") ||
+ HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
+}
+
+bool DesktopRootWindowHostX11::IsMinimized() const {
+ return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
+}
+
+
+bool DesktopRootWindowHostX11::HasCapture() const {
+ return g_current_capture == this;
+}
+
+void DesktopRootWindowHostX11::SetAlwaysOnTop(bool always_on_top) {
+ SetWMSpecState(always_on_top,
+ atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
+ None);
+}
+
+void DesktopRootWindowHostX11::SetWindowTitle(const string16& title) {
+ XStoreName(xdisplay_, xwindow_, UTF16ToUTF8(title).c_str());
+}
+
+void DesktopRootWindowHostX11::ClearNativeFocus() {
+ // This method is weird and misnamed. Instead of clearing the native focus,
+ // it sets the focus to our |content_window_|, which will trigger a cascade
+ // of focus changes into views.
+ if (content_window_ && aura::client::GetFocusClient(content_window_) &&
+ content_window_->Contains(
+ aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
+ aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
+ }
+}
+
+Widget::MoveLoopResult DesktopRootWindowHostX11::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) {
+ SetCapture();
+
+ aura::client::WindowMoveSource window_move_source =
+ source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE :
+ aura::client::WINDOW_MOVE_SOURCE_TOUCH;
+ if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
+ window_move_source) == aura::client::MOVE_SUCCESSFUL)
+ return Widget::MOVE_LOOP_SUCCESSFUL;
+
+ return Widget::MOVE_LOOP_CANCELED;
+}
+
+void DesktopRootWindowHostX11::EndMoveLoop() {
+ x11_window_move_client_->EndMoveLoop();
+}
+
+void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled(
+ bool value) {
+ // Much like the previous NativeWidgetGtk, we don't have anything to do here.
+}
+
+bool DesktopRootWindowHostX11::ShouldUseNativeFrame() {
+ return false;
+}
+
+void DesktopRootWindowHostX11::FrameTypeChanged() {
+ // Replace the frame and layout the contents. Even though we don't have a
+ // swapable glass frame like on Windows, we still replace the frame because
+ // the button assets don't update otherwise.
+ native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(true);
+}
+
+NonClientFrameView* DesktopRootWindowHostX11::CreateNonClientFrameView() {
+ return NULL;
+}
+
+void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) {
+ SetWMSpecState(fullscreen,
+ atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
+ None);
+}
+
+bool DesktopRootWindowHostX11::IsFullscreen() const {
+ return HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
+}
+
+void DesktopRootWindowHostX11::SetOpacity(unsigned char opacity) {
+ // X server opacity is in terms of 32 bit unsigned int space, and counts from
+ // the opposite direction.
+ unsigned int cardinality = opacity * 0x1010101;
+
+ if (cardinality == 0xffffffff) {
+ XDeleteProperty(xdisplay_, xwindow_,
+ atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
+ } else {
+ XChangeProperty(xdisplay_, xwindow_,
+ atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
+ XA_CARDINAL, 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&cardinality), 1);
+ }
+}
+
+void DesktopRootWindowHostX11::SetWindowIcons(
+ const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
+ // TODO(erg):
+ NOTIMPLEMENTED();
+}
+
+void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
+ // TODO(erg):
+ NOTIMPLEMENTED();
+}
+
+void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
+ // TODO(erg):
+ NOTIMPLEMENTED();
+}
+
+void DesktopRootWindowHostX11::OnNativeWidgetFocus() {
+ native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
+}
+
+void DesktopRootWindowHostX11::OnNativeWidgetBlur() {
+ if (xwindow_)
+ native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
+}
+
+void DesktopRootWindowHostX11::SetInactiveRenderingDisabled(
+ bool disable_inactive) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostX11, aura::RootWindowHost implementation:
+
+void DesktopRootWindowHostX11::SetDelegate(
+ aura::RootWindowHostDelegate* delegate) {
+ root_window_host_delegate_ = delegate;
+}
+
+aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() {
+ return root_window_;
+}
+
+gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
+ return xwindow_;
+}
+
+void DesktopRootWindowHostX11::Show() {
+ if (!window_mapped_) {
+ // Before we map the window, set size hints. Otherwise, some window managers
+ // will ignore toplevel XMoveWindow commands.
+ XSizeHints size_hints;
+ size_hints.flags = PPosition;
+ size_hints.x = bounds_.x();
+ size_hints.y = bounds_.y();
+ XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
+
+ XMapWindow(xdisplay_, xwindow_);
+
+ // We now block until our window is mapped. Some X11 APIs will crash and
+ // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
+ // asynchronous.
+ base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_);
+ window_mapped_ = true;
+ }
+}
+
+void DesktopRootWindowHostX11::Hide() {
+ if (window_mapped_) {
+ XWithdrawWindow(xdisplay_, xwindow_, 0);
+ window_mapped_ = false;
+ }
+}
+
+void DesktopRootWindowHostX11::ToggleFullScreen() {
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect DesktopRootWindowHostX11::GetBounds() const {
+ return bounds_;
+}
+
+void DesktopRootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bool size_changed = bounds_.size() != bounds.size();
+ XWindowChanges changes = {0};
+ unsigned value_mask = 0;
+
+ if (size_changed) {
+ // X11 will send an XError at our process if have a 0 sized window.
+ DCHECK_GT(bounds.width(), 0);
+ DCHECK_GT(bounds.height(), 0);
+
+ changes.width = bounds.width();
+ changes.height = bounds.height();
+ value_mask |= CWHeight | CWWidth;
+ }
+
+ if (origin_changed) {
+ changes.x = bounds.x();
+ changes.y = bounds.y();
+ value_mask |= CWX | CWY;
+ }
+ if (value_mask)
+ XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
+
+ // Assume that the resize will go through as requested, which should be the
+ // case if we're running without a window manager. If there's a window
+ // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
+ // (possibly synthetic) ConfigureNotify about the actual size and correct
+ // |bounds_| later.
+ bounds_ = bounds;
+
+ if (origin_changed)
+ native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
+ if (size_changed)
+ root_window_host_delegate_->OnHostResized(bounds.size());
+ else
+ root_window_host_delegate_->OnHostPaint(gfx::Rect(bounds.size()));
+}
+
+gfx::Insets DesktopRootWindowHostX11::GetInsets() const {
+ return gfx::Insets();
+}
+
+void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) {
+}
+
+gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const {
+ return bounds_.origin();
+}
+
+void DesktopRootWindowHostX11::SetCapture() {
+ // This is vaguely based on the old NativeWidgetGtk implementation.
+ //
+ // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
+ // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
+ // a grab that wasn't the X11 pointer grab, but was instead a manual
+ // redirection of the event. (You need to drop into GDK if you want to
+ // perform a raw X11 grab).
+
+ if (g_current_capture)
+ g_current_capture->OnCaptureReleased();
+
+ g_current_capture = this;
+
+ // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
+ // pointer grab when our NativeWidget is of type Menu. However, things work
+ // without it. Clicking inside a chrome window causes a release capture, and
+ // clicking outside causes an activation change. Since previous attempts at
+ // using XPointerGrab() to implement this have locked my X server, I'm going
+ // to skip this for now.
+}
+
+void DesktopRootWindowHostX11::ReleaseCapture() {
+ if (g_current_capture)
+ g_current_capture->OnCaptureReleased();
+}
+
+void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
+ XDefineCursor(xdisplay_, xwindow_, cursor.platform());
+}
+
+bool DesktopRootWindowHostX11::QueryMouseLocation(
+ gfx::Point* location_return) {
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(GetRootWindow());
+ if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
+ *location_return = gfx::Point(0, 0);
+ return false;
+ }
+
+ ::Window root_return, child_return;
+ int root_x_return, root_y_return, win_x_return, win_y_return;
+ unsigned int mask_return;
+ XQueryPointer(xdisplay_,
+ xwindow_,
+ &root_return,
+ &child_return,
+ &root_x_return, &root_y_return,
+ &win_x_return, &win_y_return,
+ &mask_return);
+ *location_return = gfx::Point(
+ std::max(0, std::min(bounds_.width(), win_x_return)),
+ std::max(0, std::min(bounds_.height(), win_y_return)));
+ return (win_x_return >= 0 && win_x_return < bounds_.width() &&
+ win_y_return >= 0 && win_y_return < bounds_.height());
+}
+
+bool DesktopRootWindowHostX11::ConfineCursorToRootWindow() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void DesktopRootWindowHostX11::UnConfineCursor() {
+ NOTIMPLEMENTED();
+}
+
+void DesktopRootWindowHostX11::OnCursorVisibilityChanged(bool show) {
+ // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
+ // the same tap-to-click disabling here that chromeos does.
+}
+
+void DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
+ XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
+ bounds_.x() + location.x(), bounds_.y() + location.y());
+}
+
+void DesktopRootWindowHostX11::SetFocusWhenShown(bool focus_when_shown) {
+ static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME";
+ focus_when_shown_ = focus_when_shown;
+ if (IsWindowManagerPresent() && !focus_when_shown_) {
+ ui::SetIntProperty(xwindow_,
+ k_NET_WM_USER_TIME,
+ k_NET_WM_USER_TIME,
+ 0);
+ }
+}
+
+void DesktopRootWindowHostX11::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+ DCHECK(xwindow_);
+ DCHECK(xdisplay_);
+ XEvent xevent = *native_event;
+ xevent.xany.display = xdisplay_;
+ xevent.xany.window = xwindow_;
+
+ switch (xevent.type) {
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease: {
+ // The fields used below are in the same place for all of events
+ // above. Using xmotion from XEvent's unions to avoid repeating
+ // the code.
+ xevent.xmotion.root = x_root_window_;
+ xevent.xmotion.time = CurrentTime;
+
+ gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
+ root_window_->ConvertPointToNativeScreen(&point);
+ xevent.xmotion.x_root = point.x();
+ xevent.xmotion.y_root = point.y();
+ }
+ default:
+ break;
+ }
+ XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
+}
+
+void DesktopRootWindowHostX11::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+void DesktopRootWindowHostX11::PrepareForShutdown() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostX11, private:
+
+void DesktopRootWindowHostX11::InitX11Window(
+ const Widget::InitParams& params) {
+ unsigned long attribute_mask = CWBackPixmap;
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.background_pixmap = None;
+
+ ::Atom window_type;
+ switch (params.type) {
+ case Widget::InitParams::TYPE_MENU:
+ swa.override_redirect = True;
+ attribute_mask |= CWOverrideRedirect;
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
+ break;
+ case Widget::InitParams::TYPE_TOOLTIP:
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
+ break;
+ default:
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
+ break;
+ }
+
+ xwindow_ = XCreateWindow(
+ xdisplay_, x_root_window_,
+ params.bounds.x(), params.bounds.y(),
+ params.bounds.width(), params.bounds.height(),
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ attribute_mask,
+ &swa);
+ base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_);
+
+ // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
+
+ long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
+ KeyPressMask | KeyReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask | PropertyChangeMask |
+ PointerMotionMask;
+ XSelectInput(xdisplay_, xwindow_, event_mask);
+ XFlush(xdisplay_);
+
+ if (base::MessagePumpForUI::HasXInput2())
+ ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
+
+ // TODO(erg): We currently only request window deletion events. We also
+ // should listen for activation events and anything else that GTK+ listens
+ // for, and do something useful.
+ ::Atom protocols[2];
+ protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
+ protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
+ XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
+
+ // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
+ // the desktop environment.
+ XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
+
+ // Likewise, the X server needs to know this window's pid so it knows which
+ // program to kill if the window hangs.
+ pid_t pid = getpid();
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_PID"),
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&pid), 1);
+
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&window_type), 1);
+
+ // Remove popup windows from taskbar.
+ if (params.type == Widget::InitParams::TYPE_POPUP ||
+ params.type == Widget::InitParams::TYPE_BUBBLE) {
+ Atom atom = atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR");
+
+ // Setting _NET_WM_STATE by sending a message to the root_window (with
+ // SetWMSpecState) has no effect here since the window has not yet been
+ // mapped. So we manually change the state.
+ XChangeProperty (xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_STATE"),
+ XA_ATOM,
+ 32,
+ PropModeAppend,
+ reinterpret_cast<unsigned char*>(&atom), 1);
+ }
+}
+
+// TODO(erg): This method should basically be everything I need form
+// RootWindowHostX11::RootWindowHostX11().
+aura::RootWindow* DesktopRootWindowHostX11::InitRootWindow(
+ const Widget::InitParams& params) {
+ bounds_ = params.bounds;
+
+ aura::RootWindow::CreateParams rw_params(bounds_);
+ rw_params.host = this;
+ root_window_ = new aura::RootWindow(rw_params);
+ root_window_->Init();
+ root_window_->AddChild(content_window_);
+ root_window_->SetLayoutManager(new DesktopLayoutManager(root_window_));
+ root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
+ root_window_->SetProperty(kHostForRootWindow, this);
+ root_window_host_delegate_ = root_window_;
+
+ // If we're given a parent, we need to mark ourselves as transient to another
+ // window. Otherwise activation gets screwy.
+ gfx::NativeView parent = params.parent;
+ if (!params.child && params.parent)
+ parent->AddTransientChild(content_window_);
+
+ native_widget_delegate_->OnNativeWidgetCreated(true);
+
+ capture_client_.reset(new views::DesktopCaptureClient(root_window_));
+ aura::client::SetCaptureClient(root_window_, capture_client_.get());
+
+ // Ensure that the X11DesktopHandler exists so that it dispatches activation
+ // messages to us.
+ X11DesktopHandler::get();
+
+ if (corewm::UseFocusControllerOnDesktop()) {
+ corewm::FocusController* focus_controller =
+ new corewm::FocusController(new DesktopFocusRules);
+ focus_client_.reset(focus_controller);
+ aura::client::SetFocusClient(root_window_, focus_controller);
+ aura::client::SetActivationClient(root_window_, focus_controller);
+ root_window_->AddPreTargetHandler(focus_controller);
+ } else {
+ focus_client_.reset(new aura::FocusManager);
+ aura::client::SetFocusClient(root_window_, focus_client_.get());
+ activation_client_.reset(new DesktopActivationClient(root_window_));
+ }
+
+ dispatcher_client_.reset(new DesktopDispatcherClient);
+ aura::client::SetDispatcherClient(root_window_,
+ dispatcher_client_.get());
+
+ views::DesktopNativeCursorManager* desktop_native_cursor_manager =
+ new views::DesktopNativeCursorManager(
+ root_window_,
+ scoped_ptr<DesktopCursorLoaderUpdater>(
+ new DesktopCursorLoaderUpdaterAuraX11));
+ cursor_client_.reset(
+ new views::corewm::CursorManager(
+ scoped_ptr<corewm::NativeCursorManager>(
+ desktop_native_cursor_manager)));
+ aura::client::SetCursorClient(root_window_,
+ cursor_client_.get());
+
+ position_client_.reset(new DesktopScreenPositionClient);
+ aura::client::SetScreenPositionClient(root_window_,
+ position_client_.get());
+
+ desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_);
+
+ drag_drop_client_.reset(new DesktopDragDropClientAuraX11(
+ root_window_, desktop_native_cursor_manager, xdisplay_, xwindow_));
+ aura::client::SetDragDropClient(root_window_, drag_drop_client_.get());
+
+ // TODO(erg): Unify this code once the other consumer goes away.
+ x11_window_event_filter_.reset(
+ new X11WindowEventFilter(root_window_, activation_client_.get()));
+ x11_window_event_filter_->SetUseHostWindowBorders(false);
+ desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
+ x11_window_event_filter_.get());
+
+ x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
+ aura::client::SetWindowMoveClient(root_window_,
+ x11_window_move_client_.get());
+
+ focus_client_->FocusWindow(content_window_);
+ return root_window_;
+}
+
+bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
+ // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
+ // of WM_Sn selections (where n is a screen number).
+ return XGetSelectionOwner(
+ xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
+}
+
+void DesktopRootWindowHostX11::SetWMSpecState(bool enabled,
+ ::Atom state1,
+ ::Atom state2) {
+ XEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+ xclient.type = ClientMessage;
+ xclient.xclient.window = xwindow_;
+ xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
+ xclient.xclient.format = 32;
+ xclient.xclient.data.l[0] =
+ enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
+ xclient.xclient.data.l[1] = state1;
+ xclient.xclient.data.l[2] = state2;
+ xclient.xclient.data.l[3] = 1;
+ xclient.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xclient);
+}
+
+bool DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const {
+ return window_properties_.find(atom_cache_.GetAtom(property)) !=
+ window_properties_.end();
+}
+
+void DesktopRootWindowHostX11::OnCaptureReleased() {
+ native_widget_delegate_->OnMouseCaptureLost();
+ g_current_capture = NULL;
+}
+
+void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
+ if (!g_current_capture || g_current_capture == this) {
+ root_window_host_delegate_->OnHostMouseEvent(event);
+ } else {
+ // Another DesktopRootWindowHostX11 has installed itself as
+ // capture. Translate the event's location and dispatch to the other.
+ event->ConvertLocationToTarget(root_window_,
+ g_current_capture->root_window_);
+ g_current_capture->root_window_host_delegate_->OnHostMouseEvent(event);
+ }
+}
+
+std::list<XID>& DesktopRootWindowHostX11::open_windows() {
+ if (!open_windows_)
+ open_windows_ = new std::list<XID>();
+ return *open_windows_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
+
+bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
+ XEvent* xev = event;
+
+ // May want to factor CheckXEventForConsistency(xev); into a common location
+ // since it is called here.
+ switch (xev->type) {
+ case EnterNotify:
+ case LeaveNotify: {
+ ui::MouseEvent mouse_event(xev);
+ DispatchMouseEvent(&mouse_event);
+ break;
+ }
+ case Expose: {
+ gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
+ xev->xexpose.width, xev->xexpose.height);
+ root_window_host_delegate_->OnHostPaint(damage_rect);
+ break;
+ }
+ case KeyPress: {
+ ui::KeyEvent keydown_event(xev, false);
+ root_window_host_delegate_->OnHostKeyEvent(&keydown_event);
+ break;
+ }
+ case KeyRelease: {
+ ui::KeyEvent keyup_event(xev, false);
+ root_window_host_delegate_->OnHostKeyEvent(&keyup_event);
+ break;
+ }
+ case ButtonPress: {
+ if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
+ static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
+ aura::client::UserActionClient* gesture_client =
+ aura::client::GetUserActionClient(root_window_);
+ if (gesture_client) {
+ gesture_client->OnUserAction(
+ static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
+ aura::client::UserActionClient::BACK :
+ aura::client::UserActionClient::FORWARD);
+ }
+ break;
+ }
+ } // fallthrough
+ case ButtonRelease: {
+ ui::MouseEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case FocusOut:
+ if (xev->xfocus.mode != NotifyGrab) {
+ ReleaseCapture();
+ root_window_host_delegate_->OnHostLostWindowCapture();
+ } else {
+ root_window_host_delegate_->OnHostLostMouseGrab();
+ }
+ break;
+ case ConfigureNotify: {
+ DCHECK_EQ(xwindow_, xev->xconfigure.window);
+ DCHECK_EQ(xwindow_, xev->xconfigure.event);
+ // It's possible that the X window may be resized by some other means than
+ // from within aura (e.g. the X window manager can change the size). Make
+ // sure the root window size is maintained properly.
+ int translated_x = xev->xconfigure.x;
+ int translated_y = xev->xconfigure.y;
+ if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
+ Window unused;
+ XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
+ 0, 0, &translated_x, &translated_y, &unused);
+ }
+ gfx::Rect bounds(translated_x, translated_y,
+ xev->xconfigure.width, xev->xconfigure.height);
+ bool size_changed = bounds_.size() != bounds.size();
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ previous_bounds_ = bounds_;
+ bounds_ = bounds;
+ if (size_changed)
+ root_window_host_delegate_->OnHostResized(bounds.size());
+ if (origin_changed)
+ root_window_host_delegate_->OnHostMoved(bounds_.origin());
+ break;
+ }
+ case GenericEvent: {
+ ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
+ if (!factory->ShouldProcessXI2Event(xev))
+ break;
+
+ ui::EventType type = ui::EventTypeFromNative(xev);
+ XEvent last_event;
+ int num_coalesced = 0;
+
+ switch (type) {
+ // case ui::ET_TOUCH_MOVED:
+ // num_coalesced = CoalescePendingMotionEvents(xev, &last_event);
+ // if (num_coalesced > 0)
+ // xev = &last_event;
+ // // fallthrough
+ // case ui::ET_TOUCH_PRESSED:
+ // case ui::ET_TOUCH_RELEASED: {
+ // ui::TouchEvent touchev(xev);
+ // root_window_host_delegate_->OnHostTouchEvent(&touchev);
+ // break;
+ // }
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSE_ENTERED:
+ case ui::ET_MOUSE_EXITED: {
+ if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
+ // If this is a motion event, we want to coalesce all pending motion
+ // events that are at the top of the queue.
+ num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
+ if (num_coalesced > 0)
+ xev = &last_event;
+ } else if (type == ui::ET_MOUSE_PRESSED) {
+ XIDeviceEvent* xievent =
+ static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ int button = xievent->detail;
+ if (button == kBackMouseButton || button == kForwardMouseButton) {
+ aura::client::UserActionClient* gesture_client =
+ aura::client::GetUserActionClient(
+ root_window_host_delegate_->AsRootWindow());
+ if (gesture_client) {
+ bool reverse_direction =
+ ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
+ gesture_client->OnUserAction(
+ (button == kBackMouseButton && !reverse_direction) ||
+ (button == kForwardMouseButton && reverse_direction) ?
+ aura::client::UserActionClient::BACK :
+ aura::client::UserActionClient::FORWARD);
+ }
+ break;
+ }
+ } else if (type == ui::ET_MOUSE_RELEASED) {
+ XIDeviceEvent* xievent =
+ static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ int button = xievent->detail;
+ if (button == kBackMouseButton || button == kForwardMouseButton) {
+ // We've already passed the back/forward mouse down to the user
+ // action client; we want to swallow the corresponding release.
+ break;
+ }
+ }
+ ui::MouseEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_MOUSEWHEEL: {
+ ui::MouseWheelEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_SCROLL_FLING_START:
+ case ui::ET_SCROLL_FLING_CANCEL:
+ case ui::ET_SCROLL: {
+ ui::ScrollEvent scrollev(xev);
+ root_window_host_delegate_->OnHostScrollEvent(&scrollev);
+ break;
+ }
+ case ui::ET_UNKNOWN:
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // If we coalesced an event we need to free its cookie.
+ if (num_coalesced > 0)
+ XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
+ break;
+ }
+ case MapNotify: {
+ // If there's no window manager running, we need to assign the X input
+ // focus to our host window.
+ if (!IsWindowManagerPresent() && focus_when_shown_)
+ XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
+
+ FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
+ observer_list_,
+ OnWindowMapped(xwindow_));
+ break;
+ }
+ case UnmapNotify: {
+ FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
+ observer_list_,
+ OnWindowUnmapped(xwindow_));
+ break;
+ }
+ case ClientMessage: {
+ Atom message_type = xev->xclient.message_type;
+ if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
+ Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
+ if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
+ // We have received a close message from the window manager.
+ root_window_->OnRootWindowHostCloseRequested();
+ } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
+ XEvent reply_event = *xev;
+ reply_event.xclient.window = x_root_window_;
+
+ XSendEvent(xdisplay_,
+ reply_event.xclient.window,
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &reply_event);
+ }
+ } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
+ drag_drop_client_->OnXdndEnter(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
+ drag_drop_client_->OnXdndLeave(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
+ drag_drop_client_->OnXdndPosition(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
+ drag_drop_client_->OnXdndStatus(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
+ drag_drop_client_->OnXdndFinished(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
+ drag_drop_client_->OnXdndDrop(xev->xclient);
+ }
+ break;
+ }
+ case MappingNotify: {
+ switch (xev->xmapping.request) {
+ case MappingModifier:
+ case MappingKeyboard:
+ XRefreshKeyboardMapping(&xev->xmapping);
+ root_window_->OnKeyboardMappingChanged();
+ break;
+ case MappingPointer:
+ ui::UpdateButtonMap();
+ break;
+ default:
+ NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
+ break;
+ }
+ break;
+ }
+ case MotionNotify: {
+ // Discard all but the most recent motion event that targets the same
+ // window with unchanged state.
+ XEvent last_event;
+ while (XPending(xev->xany.display)) {
+ XEvent next_event;
+ XPeekEvent(xev->xany.display, &next_event);
+ if (next_event.type == MotionNotify &&
+ next_event.xmotion.window == xev->xmotion.window &&
+ next_event.xmotion.subwindow == xev->xmotion.subwindow &&
+ next_event.xmotion.state == xev->xmotion.state) {
+ XNextEvent(xev->xany.display, &last_event);
+ xev = &last_event;
+ } else {
+ break;
+ }
+ }
+
+ ui::MouseEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case PropertyNotify: {
+ // Get our new window property state if the WM has told us its changed.
+ ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
+
+ std::vector< ::Atom> atom_list;
+ if (xev->xproperty.atom == state &&
+ ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
+ window_properties_.clear();
+ std::copy(atom_list.begin(), atom_list.end(),
+ inserter(window_properties_, window_properties_.begin()));
+
+ if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
+ // If we have restored bounds, but WM_STATE no longer claims to be
+ // maximized, we should clear our restored bounds.
+ restored_bounds_ = gfx::Rect();
+ } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
+ // The request that we become maximized originated from a different
+ // process. |bounds_| already contains our maximized bounds. Do a
+ // best effort attempt to get restored bounds by setting it to our
+ // previously set bounds (and if we get this wrong, we aren't any
+ // worse off since we'd otherwise be returning our maximized bounds).
+ restored_bounds_ = previous_bounds_;
+ }
+
+ // Now that we have different window properties, we may need to
+ // relayout the window. (The windows code doesn't need this because
+ // their window change is synchronous.)
+ //
+ // TODO(erg): While this does work, there's a quick flash showing the
+ // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
+ // those parts of the UI because we receive the sizing event from the
+ // window manager before we receive the event that changes the
+ // fullscreen state. Unsure what to do about that.
+ Widget* widget = native_widget_delegate_->AsWidget();
+ NonClientView* non_client_view = widget->non_client_view();
+ // non_client_view may be NULL, especially during creation.
+ if (non_client_view) {
+ non_client_view->client_view()->InvalidateLayout();
+ non_client_view->InvalidateLayout();
+ }
+ widget->GetRootView()->Layout();
+ }
+ break;
+ }
+ case SelectionNotify: {
+ drag_drop_client_->OnSelectionNotify(xev->xselection);
+ break;
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHost, public:
+
+// static
+DesktopRootWindowHost* DesktopRootWindowHost::Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds) {
+ return new DesktopRootWindowHostX11(native_widget_delegate,
+ desktop_native_widget_aura,
+ initial_bounds);
+}
+
+// static
+ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
+ const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+ if (linux_ui) {
+ ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
+ if (native_theme)
+ return native_theme;
+ }
+
+ return ui::NativeTheme::instance();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
new file mode 100644
index 00000000000..c3630293dc8
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
@@ -0,0 +1,269 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_X11_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_X11_H_
+
+#include <X11/Xlib.h>
+
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/root_window_host.h"
+#include "ui/base/cursor/cursor_loader_x11.h"
+#include "ui/base/x/x11_atom_cache.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+
+namespace aura {
+namespace client {
+class FocusClient;
+class ScreenPositionClient;
+}
+}
+
+namespace views {
+class DesktopActivationClient;
+class DesktopCaptureClient;
+class DesktopDragDropClientAuraX11;
+class DesktopDispatcherClient;
+class DesktopRootWindowHostObserverX11;
+class X11DesktopWindowMoveClient;
+class X11WindowEventFilter;
+
+namespace corewm {
+class CursorManager;
+}
+
+class VIEWS_EXPORT DesktopRootWindowHostX11 :
+ public DesktopRootWindowHost,
+ public aura::RootWindowHost,
+ public base::MessageLoop::Dispatcher {
+ public:
+ DesktopRootWindowHostX11(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura,
+ const gfx::Rect& initial_bounds);
+ virtual ~DesktopRootWindowHostX11();
+
+ // A way of converting an X11 |xid| host window into a |content_window_|.
+ static aura::Window* GetContentWindowForXID(XID xid);
+
+ // A way of converting an X11 |xid| host window into this object.
+ static DesktopRootWindowHostX11* GetHostForXID(XID xid);
+
+ // Get all open top-level windows. This includes windows that may not be
+ // visible.
+ static std::vector<aura::Window*> GetAllOpenWindows();
+
+ // Called by X11DesktopHandler to notify us that the native windowing system
+ // has changed our activation.
+ void HandleNativeWidgetActivationChanged(bool active);
+
+ void AddObserver(views::DesktopRootWindowHostObserverX11* observer);
+ void RemoveObserver(views::DesktopRootWindowHostObserverX11* observer);
+
+ // Deallocates the internal list of open windows.
+ static void CleanUpWindowList();
+
+ protected:
+ // Overridden from DesktopRootWindowHost:
+ virtual aura::RootWindow* Init(aura::Window* content_window,
+ const Widget::InitParams& params) OVERRIDE;
+ virtual void InitFocus(aura::Window* window) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual aura::RootWindowHost* AsRootWindowHost() OVERRIDE;
+ virtual void ShowWindowWithState(ui::WindowShowState show_state) OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion native_region) OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual void SetWindowTitle(const string16& title) OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual bool ShouldUseNativeFrame() OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void OnNativeWidgetFocus() OVERRIDE;
+ virtual void OnNativeWidgetBlur() OVERRIDE;
+ virtual void SetInactiveRenderingDisabled(bool disable_inactive) OVERRIDE;
+
+ // Overridden from aura::RootWindowHost:
+ virtual void SetDelegate(aura::RootWindowHostDelegate* delegate) OVERRIDE;
+ virtual aura::RootWindow* GetRootWindow() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ToggleFullScreen() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Insets GetInsets() const OVERRIDE;
+ virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
+ virtual bool ConfineCursorToRootWindow() OVERRIDE;
+ virtual void UnConfineCursor() OVERRIDE;
+ virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
+ virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
+ virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void PrepareForShutdown() OVERRIDE;
+
+private:
+ // Initializes our X11 surface to draw on. This method performs all
+ // initialization related to talking to the X11 server.
+ void InitX11Window(const Widget::InitParams& params);
+
+ // Creates an aura::RootWindow to contain the |content_window|, along with
+ // all aura client objects that direct behavior.
+ aura::RootWindow* InitRootWindow(const Widget::InitParams& params);
+
+ // Returns true if there's an X window manager present... in most cases. Some
+ // window managers (notably, ion3) don't implement enough of ICCCM for us to
+ // detect that they're there.
+ bool IsWindowManagerPresent();
+
+ // Sends a message to the x11 window manager, enabling or disabling the
+ // states |state1| and |state2|.
+ void SetWMSpecState(bool enabled, ::Atom state1, ::Atom state2);
+
+ // Checks if the window manager has set a specific state.
+ bool HasWMSpecProperty(const char* property) const;
+
+ // Called when another DRWHL takes capture, or when capture is released
+ // entirely.
+ void OnCaptureReleased();
+
+ // Dispatches a mouse event, taking mouse capture into account. If a
+ // different host has capture, we translate the event to its coordinate space
+ // and dispatch it to that host instead.
+ void DispatchMouseEvent(ui::MouseEvent* event);
+
+ // See comment for variable open_windows_.
+ static std::list<XID>& open_windows();
+
+ // Overridden from Dispatcher:
+ virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ base::WeakPtrFactory<DesktopRootWindowHostX11> close_widget_factory_;
+
+ // X11 things
+ // The display and the native X window hosting the root window.
+ Display* xdisplay_;
+ ::Window xwindow_;
+
+ // The native root window.
+ ::Window x_root_window_;
+
+ ui::X11AtomCache atom_cache_;
+
+ // Is the window mapped to the screen?
+ bool window_mapped_;
+
+ // The bounds of |xwindow_|.
+ gfx::Rect bounds_;
+
+ // Whenever the bounds are set, we keep the previous set of bounds around so
+ // we can have a better chance of getting the real |restored_bounds_|. Window
+ // managers tend to send a Configure message with the maximized bounds, and
+ // then set the window maximized property. (We don't rely on this for when we
+ // request that the window be maximized, only when we detect that some other
+ // process has requested that we become the maximized window.)
+ gfx::Rect previous_bounds_;
+
+ // The bounds of our window before we were maximized.
+ gfx::Rect restored_bounds_;
+
+ // True if the window should be focused when the window is shown.
+ bool focus_when_shown_;
+
+ // The window manager state bits.
+ std::set< ::Atom> window_properties_;
+
+ // We are owned by the RootWindow, but we have to have a back pointer to it.
+ aura::RootWindow* root_window_;
+
+ // aura:: objects that we own.
+ scoped_ptr<DesktopCaptureClient> capture_client_;
+ scoped_ptr<aura::client::FocusClient> focus_client_;
+ scoped_ptr<DesktopActivationClient> activation_client_;
+ scoped_ptr<views::corewm::CursorManager> cursor_client_;
+ scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
+ scoped_ptr<aura::client::ScreenPositionClient> position_client_;
+ scoped_ptr<DesktopDragDropClientAuraX11> drag_drop_client_;
+
+ // Current Aura cursor.
+ gfx::NativeCursor current_cursor_;
+
+ scoped_ptr<X11WindowEventFilter> x11_window_event_filter_;
+ scoped_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;
+
+ // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
+ // instead of providing this route back to Widget.
+ internal::NativeWidgetDelegate* native_widget_delegate_;
+
+ DesktopNativeWidgetAura* desktop_native_widget_aura_;
+
+ aura::RootWindowHostDelegate* root_window_host_delegate_;
+ aura::Window* content_window_;
+
+ ObserverList<DesktopRootWindowHostObserverX11> observer_list_;
+
+ // The current root window host that has capture. While X11 has something
+ // like Windows SetCapture()/ReleaseCapture(), it is entirely implicit and
+ // there are no notifications when this changes. We need to track this so we
+ // can notify widgets when they have lost capture, which controls a bunch of
+ // things in views like hiding menus.
+ static DesktopRootWindowHostX11* g_current_capture;
+
+ // A list of all (top-level) windows that have been created but not yet
+ // destroyed.
+ static std::list<XID>* open_windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopRootWindowHostX11);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_X11_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen.h b/chromium/ui/views/widget/desktop_aura/desktop_screen.h
new file mode 100644
index 00000000000..ad66bd41575
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_H_
+
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Screen;
+}
+
+namespace views {
+
+// Creates a Screen that represents the screen of the environment that hosts
+// a RootWindowHost. Caller owns the result.
+VIEWS_EXPORT gfx::Screen* CreateDesktopScreen();
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
new file mode 100644
index 00000000000..2ca556c3979
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/point_conversions.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+
+namespace views {
+
+namespace {
+
+gfx::Point GetOrigin(const aura::RootWindow* root_window) {
+ gfx::Point origin_in_pixels = root_window->GetHostOrigin();
+ aura::RootWindow* window = const_cast<aura::RootWindow*>(root_window);
+ float scale = gfx::Screen::GetScreenFor(window)->
+ GetDisplayNearestWindow(window).device_scale_factor();
+ return gfx::ToFlooredPoint(
+ gfx::ScalePoint(origin_in_pixels, 1 / scale));
+}
+
+// Returns true if bounds passed to window are treated as though they are in
+// screen coordinates.
+bool PositionWindowInScreenCoordinates(aura::Window* window) {
+ if (window->type() == aura::client::WINDOW_TYPE_POPUP ||
+ window->type() == aura::client::WINDOW_TYPE_TOOLTIP)
+ return true;
+
+ Widget* widget = Widget::GetWidgetForNativeView(window);
+ return widget && widget->is_top_level();
+}
+
+} // namespace
+
+DesktopScreenPositionClient::DesktopScreenPositionClient() {
+}
+
+DesktopScreenPositionClient::~DesktopScreenPositionClient() {
+}
+
+void DesktopScreenPositionClient::ConvertPointToScreen(
+ const aura::Window* window, gfx::Point* point) {
+ const aura::RootWindow* root_window = window->GetRootWindow();
+ aura::Window::ConvertPointToTarget(window, root_window, point);
+ gfx::Point origin = GetOrigin(root_window);
+ point->Offset(origin.x(), origin.y());
+}
+
+void DesktopScreenPositionClient::ConvertPointFromScreen(
+ const aura::Window* window, gfx::Point* point) {
+ const aura::RootWindow* root_window = window->GetRootWindow();
+ gfx::Point origin = GetOrigin(root_window);
+ point->Offset(-origin.x(), -origin.y());
+ aura::Window::ConvertPointToTarget(root_window, window, point);
+}
+
+void DesktopScreenPositionClient::ConvertHostPointToScreen(
+ aura::RootWindow* window, gfx::Point* point) {
+ ConvertPointToScreen(window, point);
+}
+
+void DesktopScreenPositionClient::SetBounds(
+ aura::Window* window,
+ const gfx::Rect& bounds,
+ const gfx::Display& display) {
+ // TODO: Use the 3rd parameter, |display|.
+ aura::RootWindow* root = window->GetRootWindow();
+
+ if (PositionWindowInScreenCoordinates(window)) {
+ // The caller expects windows we consider "embedded" to be placed in the
+ // screen coordinate system. So we need to offset the root window's
+ // position (which is in screen coordinates) from these bounds.
+
+ gfx::Point origin = bounds.origin();
+ aura::Window::ConvertPointToTarget(window->parent(), root, &origin);
+
+ gfx::Point host_origin = GetOrigin(root);
+ origin.Offset(-host_origin.x(), -host_origin.y());
+ window->SetBounds(gfx::Rect(origin, bounds.size()));
+ return;
+ }
+
+ DesktopNativeWidgetAura* desktop_native_widget =
+ DesktopNativeWidgetAura::ForWindow(window);
+ if (desktop_native_widget) {
+ root->SetHostBounds(bounds);
+ // Setting bounds of root resizes |window|.
+ } else {
+ window->SetBounds(bounds);
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h
new file mode 100644
index 00000000000..479a1cc4b3d
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_POSITION_CLIENT_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_POSITION_CLIENT_H_
+
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// Client that always offsets by the toplevel RootWindow of the passed
+// in child NativeWidgetAura.
+class VIEWS_EXPORT DesktopScreenPositionClient
+ : public aura::client::ScreenPositionClient {
+ public:
+ DesktopScreenPositionClient();
+ virtual ~DesktopScreenPositionClient();
+
+ // aura::client::ScreenPositionClient overrides:
+ virtual void ConvertPointToScreen(const aura::Window* window,
+ gfx::Point* point) OVERRIDE;
+ virtual void ConvertPointFromScreen(const aura::Window* window,
+ gfx::Point* point) OVERRIDE;
+ virtual void ConvertHostPointToScreen(aura::RootWindow* window,
+ gfx::Point* point) OVERRIDE;
+ virtual void SetBounds(aura::Window* window,
+ const gfx::Rect& bounds,
+ const gfx::Display& display) OVERRIDE;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_POSITION_CLIENT_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
new file mode 100644
index 00000000000..bb1cd8b08ac
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2013 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/views/test/views_test_base.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace views {
+
+typedef ViewsTestBase DesktopScreenPositionClientTest;
+
+// Verifies setting the bounds of a dialog parented to a Widget with a
+// DesktopNativeWidgetAura is positioned correctly.
+TEST_F(DesktopScreenPositionClientTest, PositionDialog) {
+ Widget parent_widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.bounds = gfx::Rect(10, 11, 200, 200);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
+ parent_widget.Init(init_params);
+ // parent_widget.Show();
+
+ // Owned by |dialog|.
+ DialogDelegateView* dialog_delegate_view = new DialogDelegateView;
+ // Owned by |parent_widget|.
+ Widget* dialog = DialogDelegate::CreateDialogWidget(
+ dialog_delegate_view,
+ NULL,
+ parent_widget.GetNativeView());
+ dialog->SetBounds(gfx::Rect(11, 12, 200, 200));
+ EXPECT_EQ("11,12", dialog->GetWindowBoundsInScreen().origin().ToString());
+}
+
+// Verifies that setting the bounds of a control parented to something other
+// than the root window is positioned correctly.
+TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
+ Widget widget1;
+ Widget widget2;
+ Widget widget3;
+ gfx::Point origin = gfx::Point(16, 16);
+
+ // Use a custom frame type. By default we will choose a native frame when
+ // aero glass is enabled, and this complicates the logic surrounding origin
+ // computation, making it difficult to compute the expected origin location.
+ widget1.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM);
+ widget2.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM);
+ widget3.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM);
+
+ // Create 3 windows. A root window, an arbitrary window parented to the root
+ // but NOT positioned at (0,0) relative to the root, and then a third window
+ // parented to the second, also not positioned at (0,0).
+ Widget::InitParams params1 =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params1.bounds = gfx::Rect(origin, gfx::Size(700, 600));
+ params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params1.native_widget = new DesktopNativeWidgetAura(&widget1);
+ widget1.Init(params1);
+
+ Widget::InitParams params2 =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params2.bounds = gfx::Rect(origin, gfx::Size(600, 500));
+ params2.parent = widget1.GetNativeView();
+ params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params2.child = true;
+ widget2.Init(params2);
+
+ Widget::InitParams params3 =
+ CreateParams(Widget::InitParams::TYPE_CONTROL);
+ params3.parent = widget2.GetNativeView();
+ params3.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params3.child = true;
+ params3.bounds = gfx::Rect(origin, gfx::Size(500, 400));
+ widget3.Init(params3);
+
+ // The origin of the 3rd window should be the sum of all parent origins.
+ gfx::Point expected_origin(origin.x() * 3, origin.y() * 3);
+ gfx::Rect expected_bounds(expected_origin, gfx::Size(500, 400));
+ gfx::Rect actual_bounds(widget3.GetWindowBoundsInScreen());
+ EXPECT_EQ(expected_bounds.ToString(), actual_bounds.ToString());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
new file mode 100644
index 00000000000..93721bce353
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_screen_win.h"
+
+#include "base/logging.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/root_window_host.h"
+#include "ui/gfx/display.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+
+namespace {
+
+MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) {
+ MONITORINFO monitor_info = { 0 };
+ monitor_info.cbSize = sizeof(monitor_info);
+ GetMonitorInfo(monitor, &monitor_info);
+ return monitor_info;
+}
+
+gfx::Display GetDisplay(MONITORINFO& monitor_info) {
+ // TODO(oshima): Implement ID and Observer.
+ gfx::Display display(0, gfx::Rect(monitor_info.rcMonitor));
+ display.set_work_area(gfx::Rect(monitor_info.rcWork));
+ return display;
+}
+
+} // namespace
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopScreenWin, public:
+
+DesktopScreenWin::DesktopScreenWin() {
+}
+
+DesktopScreenWin::~DesktopScreenWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopScreenWin, gfx::ScreenWin implementation:
+
+bool DesktopScreenWin::IsDIPEnabled() {
+ return true;
+}
+
+gfx::Display DesktopScreenWin::GetDisplayMatching(
+ const gfx::Rect& match_rect) const {
+ return GetDisplayNearestPoint(match_rect.CenterPoint());
+}
+
+HWND DesktopScreenWin::GetHWNDFromNativeView(gfx::NativeView window) const {
+ aura::RootWindow* root_window = window->GetRootWindow();
+ return root_window ? root_window->GetAcceleratedWidget() : NULL;
+}
+
+gfx::NativeWindow DesktopScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
+ return (::IsWindow(hwnd)) ?
+ DesktopRootWindowHostWin::GetContentWindowForHWND(hwnd) : NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+gfx::Screen* CreateDesktopScreen() {
+ return new DesktopScreenWin;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
new file mode 100644
index 00000000000..3225d61709e
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_WIN_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_WIN_H_
+
+#include "ui/gfx/screen_win.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class VIEWS_EXPORT DesktopScreenWin : public gfx::ScreenWin {
+public:
+ DesktopScreenWin();
+ virtual ~DesktopScreenWin();
+
+ private:
+ // Overridden from gfx::ScreenWin:
+ virtual bool IsDIPEnabled() OVERRIDE;
+ virtual gfx::Display GetDisplayMatching(
+ const gfx::Rect& match_rect) const OVERRIDE;
+ virtual HWND GetHWNDFromNativeView(gfx::NativeView window) const OVERRIDE;
+ virtual gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopScreenWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_WIN_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
new file mode 100644
index 00000000000..77dbaa497a7
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+
+#include <X11/Xlib.h>
+
+// It clashes with out RootWindow.
+#undef RootWindow
+
+#include "base/logging.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/root_window_host.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/screen.h"
+
+namespace {
+
+// TODO(erg): This method is a temporary hack, until we can reliably extract
+// location data out of XRandR.
+gfx::Size GetPrimaryDisplaySize() {
+ ::Display* display = ui::GetXDisplay();
+ ::Screen* screen = DefaultScreenOfDisplay(display);
+ int width = WidthOfScreen(screen);
+ int height = HeightOfScreen(screen);
+
+ return gfx::Size(width, height);
+}
+
+class DesktopScreenX11 : public gfx::Screen {
+ public:
+ DesktopScreenX11();
+ virtual ~DesktopScreenX11();
+
+ // Overridden from gfx::Screen:
+ virtual bool IsDIPEnabled() OVERRIDE;
+ virtual gfx::Point GetCursorScreenPoint() OVERRIDE;
+ virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE;
+ virtual int GetNumDisplays() OVERRIDE;
+ virtual gfx::Display GetDisplayNearestWindow(
+ gfx::NativeView window) const OVERRIDE;
+ virtual gfx::Display GetDisplayNearestPoint(
+ const gfx::Point& point) const OVERRIDE;
+ virtual gfx::Display GetDisplayMatching(
+ const gfx::Rect& match_rect) const OVERRIDE;
+ virtual gfx::Display GetPrimaryDisplay() const OVERRIDE;
+ virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopScreenX11, public:
+
+DesktopScreenX11::DesktopScreenX11() {
+}
+
+DesktopScreenX11::~DesktopScreenX11() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopScreenX11, gfx::Screen implementation:
+
+bool DesktopScreenX11::IsDIPEnabled() {
+ return false;
+}
+
+gfx::Point DesktopScreenX11::GetCursorScreenPoint() {
+ Display* display = ui::GetXDisplay();
+
+ ::Window root, child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ XQueryPointer(display,
+ DefaultRootWindow(display),
+ &root,
+ &child,
+ &root_x,
+ &root_y,
+ &win_x,
+ &win_y,
+ &mask);
+
+ return gfx::Point(root_x, root_y);
+}
+
+gfx::NativeWindow DesktopScreenX11::GetWindowAtCursorScreenPoint() {
+ // TODO(erg): Implement using the discussion at
+ // http://codereview.chromium.org/10279005/
+ return NULL;
+}
+
+int DesktopScreenX11::GetNumDisplays() {
+ // TODO(erg): Figure this out with oshima or piman because I have no clue
+ // about the XRandR implications here.
+ return 1;
+}
+
+gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
+ gfx::NativeView window) const {
+ // TODO(erg): Do the right thing once we know what that is.
+ return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize()));
+}
+
+gfx::Display DesktopScreenX11::GetDisplayNearestPoint(
+ const gfx::Point& point) const {
+ // TODO(erg): Do the right thing once we know what that is.
+ return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize()));
+}
+
+gfx::Display DesktopScreenX11::GetDisplayMatching(
+ const gfx::Rect& match_rect) const {
+ // TODO(erg): Do the right thing once we know what that is.
+ return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize()));
+}
+
+gfx::Display DesktopScreenX11::GetPrimaryDisplay() const {
+ // TODO(erg): Do the right thing once we know what that is.
+ return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize()));
+}
+
+void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) {
+ // TODO(erg|oshima): Do the right thing once we know what that is.
+ // crbug.com/122863
+}
+void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
+ // TODO(erg|oshima): Do the right thing once we know what that is.
+ // crbug.com/122863
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace views {
+
+gfx::Screen* CreateDesktopScreen() {
+ return new DesktopScreenX11;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
new file mode 100644
index 00000000000..46906992fce
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
+
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/env.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/views/widget/desktop_aura/desktop_activation_client.h"
+
+#if !defined(OS_CHROMEOS)
+#include "ui/views/ime/input_method.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+#endif
+
+namespace {
+
+const char* kAtomsToCache[] = {
+ "_NET_ACTIVE_WINDOW",
+ NULL
+};
+
+// Our global instance. Deleted when our Env() is deleted.
+views::X11DesktopHandler* g_handler = NULL;
+
+} // namespace
+
+namespace views {
+
+// static
+X11DesktopHandler* X11DesktopHandler::get() {
+ if (!g_handler)
+ g_handler = new X11DesktopHandler;
+
+ return g_handler;
+}
+
+X11DesktopHandler::X11DesktopHandler()
+ : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ current_window_(None),
+ atom_cache_(xdisplay_, kAtomsToCache) {
+ base::MessagePumpAuraX11::Current()->AddDispatcherForRootWindow(this);
+ aura::Env::GetInstance()->AddObserver(this);
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(xdisplay_, x_root_window_, &attr);
+ XSelectInput(xdisplay_, x_root_window_,
+ attr.your_event_mask | PropertyChangeMask |
+ StructureNotifyMask | SubstructureNotifyMask);
+}
+
+X11DesktopHandler::~X11DesktopHandler() {
+ aura::Env::GetInstance()->RemoveObserver(this);
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForRootWindow(this);
+}
+
+void X11DesktopHandler::ActivateWindow(::Window window) {
+ DCHECK_EQ(base::MessagePumpAuraX11::GetDefaultXDisplay(), xdisplay_);
+
+ XEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+ xclient.type = ClientMessage;
+ xclient.xclient.window = window;
+ xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
+ xclient.xclient.format = 32;
+ xclient.xclient.data.l[0] = 1; // Specified we are an app.
+ xclient.xclient.data.l[1] = CurrentTime;
+ xclient.xclient.data.l[2] = None;
+ xclient.xclient.data.l[3] = 0;
+ xclient.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xclient);
+}
+
+bool X11DesktopHandler::IsActiveWindow(::Window window) const {
+ return window == current_window_;
+}
+
+bool X11DesktopHandler::Dispatch(const base::NativeEvent& event) {
+ // Check for a change to the active window.
+ switch (event->type) {
+ case PropertyNotify: {
+ ::Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
+
+ if (event->xproperty.window == x_root_window_ &&
+ event->xproperty.atom == active_window) {
+ int window;
+ if (ui::GetIntProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) &&
+ window) {
+ OnActiveWindowChanged(static_cast< ::Window>(window));
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+void X11DesktopHandler::OnWindowInitialized(aura::Window* window) {
+}
+
+void X11DesktopHandler::OnWillDestroyEnv() {
+ g_handler = NULL;
+ delete this;
+}
+
+void X11DesktopHandler::OnActiveWindowChanged(::Window xid) {
+ DesktopRootWindowHostX11* old_host =
+ views::DesktopRootWindowHostX11::GetHostForXID(current_window_);
+ if (old_host)
+ old_host->HandleNativeWidgetActivationChanged(false);
+
+ DesktopRootWindowHostX11* new_host =
+ views::DesktopRootWindowHostX11::GetHostForXID(xid);
+ if (new_host)
+ new_host->HandleNativeWidgetActivationChanged(true);
+
+ current_window_ = xid;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
new file mode 100644
index 00000000000..8cda9eeaaab
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_H_
+
+#include <X11/Xlib.h>
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/env_observer.h"
+#include "ui/base/x/x11_atom_cache.h"
+#include "ui/views/views_export.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace views {
+
+// A singleton that owns global objects related to the desktop and listens for
+// X11 events on the X11 root window. Destroys itself when aura::Env is
+// deleted.
+class VIEWS_EXPORT X11DesktopHandler : public base::MessageLoop::Dispatcher,
+ public aura::EnvObserver {
+ public:
+ // Returns the singleton handler.
+ static X11DesktopHandler* get();
+
+ // Sends a request to the window manager to activate |window|.
+ void ActivateWindow(::Window window);
+
+ // Checks if the current active window is |window|.
+ bool IsActiveWindow(::Window window) const;
+
+ // Overridden from MessageLoop::Dispatcher:
+ virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ // Overridden from aura::EnvObserver:
+ virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
+ virtual void OnWillDestroyEnv() OVERRIDE;
+
+ private:
+ explicit X11DesktopHandler();
+ virtual ~X11DesktopHandler();
+
+ // Handles changes in activation.
+ void OnActiveWindowChanged(::Window window);
+
+ // The display and the native X window hosting the root window.
+ Display* xdisplay_;
+
+ // The native root window.
+ ::Window x_root_window_;
+
+ // The activated window.
+ ::Window current_window_;
+
+ ui::X11AtomCache atom_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11DesktopHandler);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
new file mode 100644
index 00000000000..d28de216dce
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
+
+#include <X11/Xlib.h>
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include "base/debug/stack_trace.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_aurax11.h"
+#include "base/run_loop.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/events/event.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/screen.h"
+
+namespace views {
+
+X11DesktopWindowMoveClient::X11DesktopWindowMoveClient()
+ : move_loop_(this),
+ root_window_(NULL) {
+}
+
+X11DesktopWindowMoveClient::~X11DesktopWindowMoveClient() {}
+
+void X11DesktopWindowMoveClient::OnMouseMovement(XMotionEvent* event) {
+ gfx::Point cursor_point(event->x_root, event->y_root);
+ gfx::Point system_loc = cursor_point - window_offset_;
+ root_window_->SetHostBounds(gfx::Rect(
+ system_loc, root_window_->GetHostSize()));
+}
+
+void X11DesktopWindowMoveClient::OnMouseReleased() {
+ EndMoveLoop();
+}
+
+void X11DesktopWindowMoveClient::OnMoveLoopEnded() {
+ root_window_ = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostLinux, aura::client::WindowMoveClient implementation:
+
+aura::client::WindowMoveResult X11DesktopWindowMoveClient::RunMoveLoop(
+ aura::Window* source,
+ const gfx::Vector2d& drag_offset,
+ aura::client::WindowMoveSource move_source) {
+ window_offset_ = drag_offset;
+ root_window_ = source->GetRootWindow();
+
+ bool success = move_loop_.RunMoveLoop(source, root_window_->last_cursor());
+ return success ? aura::client::MOVE_SUCCESSFUL : aura::client::MOVE_CANCELED;
+}
+
+void X11DesktopWindowMoveClient::EndMoveLoop() {
+ move_loop_.EndMoveLoop();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
new file mode 100644
index 00000000000..1a8b5884ac1
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
+
+#include <X11/Xlib.h>
+
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/client/window_move_client.h"
+#include "ui/gfx/point.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
+
+namespace aura {
+class RootWindow;
+}
+
+namespace views {
+
+// When we're dragging tabs, we need to manually position our window.
+class VIEWS_EXPORT X11DesktopWindowMoveClient :
+ public views::X11WholeScreenMoveLoopDelegate,
+ public aura::client::WindowMoveClient {
+ public:
+ X11DesktopWindowMoveClient();
+ virtual ~X11DesktopWindowMoveClient();
+
+ // Overridden from X11WholeScreenMoveLoopDelegate:
+ virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
+ virtual void OnMouseReleased() OVERRIDE;
+ virtual void OnMoveLoopEnded() OVERRIDE;
+
+ // Overridden from aura::client::WindowMoveClient:
+ virtual aura::client::WindowMoveResult RunMoveLoop(
+ aura::Window* window,
+ const gfx::Vector2d& drag_offset,
+ aura::client::WindowMoveSource move_source) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+
+ private:
+ X11WholeScreenMoveLoop move_loop_;
+
+ // We need to keep track of this so we can actually move it when reacting to
+ // mouse events.
+ aura::RootWindow* root_window_;
+
+ // Our cursor offset from the top left window origin when the drag
+ // started. Used to calculate the window's new bounds relative to the current
+ // location of the cursor.
+ gfx::Vector2d window_offset_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
new file mode 100644
index 00000000000..d04dd88cb2f
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
+
+#include <X11/Xlib.h>
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include "base/debug/stack_trace.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_aurax11.h"
+#include "base/run_loop.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/events/event.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/screen.h"
+
+namespace views {
+
+X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(
+ X11WholeScreenMoveLoopDelegate* delegate)
+ : delegate_(delegate),
+ in_move_loop_(false),
+ grab_input_window_(None) /*,
+ root_window_(NULL)*/ {
+}
+
+X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation:
+
+bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
+ XEvent* xev = event;
+
+ // Note: the escape key is handled in the tab drag controller, which has
+ // keyboard focus even though we took pointer grab.
+ switch (xev->type) {
+ case MotionNotify: {
+ delegate_->OnMouseMovement(&xev->xmotion);
+ break;
+ }
+ case ButtonRelease: {
+ if (xev->xbutton.button == Button1) {
+ // Assume that drags are being done with the left mouse button. Only
+ // break the drag if the left mouse button was released.
+ delegate_->OnMouseReleased();
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostLinux, aura::client::WindowMoveClient implementation:
+
+bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
+ gfx::NativeCursor cursor) {
+ DCHECK(!in_move_loop_); // Can only handle one nested loop at a time.
+ in_move_loop_ = true;
+
+ Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
+
+ // Creates an invisible, InputOnly toplevel window. This window will receive
+ // all mouse movement for drags. It turns out that normal windows doing a
+ // grab doesn't redirect pointer motion events if the pointer isn't over the
+ // grabbing window. But InputOnly windows are able to grab everything. This
+ // is what GTK+ does, and I found a patch to KDE that did something similar.
+ unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
+ StructureNotifyMask;
+ swa.override_redirect = True;
+ grab_input_window_ = XCreateWindow(
+ display,
+ DefaultRootWindow(display),
+ -100, -100, 10, 10,
+ 0, 0, InputOnly, CopyFromParent,
+ attribute_mask, &swa);
+ base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(
+ this, grab_input_window_);
+
+ // Wait for the window to be mapped. If we don't, XGrabPointer fails.
+ XMapRaised(display, grab_input_window_);
+ base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(
+ grab_input_window_);
+
+ if (!GrabPointerWithCursor(cursor))
+ return false;
+
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
+ base::RunLoop run_loop(aura::Env::GetInstance()->GetDispatcher());
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ return true;
+}
+
+void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
+ DCHECK(in_move_loop_);
+ GrabPointerWithCursor(cursor);
+}
+
+void X11WholeScreenMoveLoop::EndMoveLoop() {
+ if (!in_move_loop_)
+ return;
+
+ // TODO(erg): Is this ungrab the cause of having to click to give input focus
+ // on drawn out windows? Not ungrabbing here screws the X server until I kill
+ // the chrome process.
+
+ // Ungrab before we let go of the window.
+ Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
+ XUngrabPointer(display, CurrentTime);
+
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(
+ grab_input_window_);
+ delegate_->OnMoveLoopEnded();
+ XDestroyWindow(display, grab_input_window_);
+
+ in_move_loop_ = false;
+ quit_closure_.Run();
+}
+
+bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) {
+ Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
+ XGrabServer(display);
+ XUngrabPointer(display, CurrentTime);
+ int ret = XGrabPointer(
+ display,
+ grab_input_window_,
+ False,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ cursor.platform(),
+ CurrentTime);
+ XUngrabServer(display);
+ if (ret != GrabSuccess) {
+ DLOG(ERROR) << "Grabbing new tab for dragging failed: "
+ << ui::GetX11ErrorString(display, ret);
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
new file mode 100644
index 00000000000..ceff84f9fb2
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2013 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_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
+
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+
+// Runs a nested message loop and grabs the mouse. This is used to implement
+// dragging.
+class X11WholeScreenMoveLoop : public base::MessageLoop::Dispatcher {
+ public:
+ explicit X11WholeScreenMoveLoop(X11WholeScreenMoveLoopDelegate* delegate);
+ virtual ~X11WholeScreenMoveLoop();
+
+ // Overridden from base::MessageLoop::Dispatcher:
+ virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ // Runs the nested message loop. While the mouse is grabbed, use |cursor| as
+ // the mouse cursor. Returns true if there we were able to grab the pointer
+ // and run the move loop.
+ bool RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor);
+
+ // Updates the cursor while the move loop is running.
+ void UpdateCursor(gfx::NativeCursor cursor);
+
+ // Ends the RunMoveLoop() that's currently in progress.
+ void EndMoveLoop();
+
+ private:
+ // Grabs the pointer, setting the mouse cursor to |cursor|. Returns true if
+ // the grab was successful.
+ bool GrabPointerWithCursor(gfx::NativeCursor cursor);
+
+ X11WholeScreenMoveLoopDelegate* delegate_;
+
+ // Are we running a nested message loop from RunMoveLoop()?
+ bool in_move_loop_;
+
+ // An invisible InputOnly window . We create this window so we can track the
+ // cursor wherever it goes on screen during a drag, since normal windows
+ // don't receive pointer motion events outside of their bounds.
+ ::Window grab_input_window_;
+
+ base::Closure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11WholeScreenMoveLoop);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h
new file mode 100644
index 00000000000..69f63be1287
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2013 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_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_DELEGATE_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_DELEGATE_H_
+
+#include <X11/Xlib.h>
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+namespace views {
+
+// Receives mouse events while the X11WholeScreenMoveLoop is tracking a drag on
+// the screen.
+class X11WholeScreenMoveLoopDelegate {
+ public:
+ // Called when we receive a motion event.
+ virtual void OnMouseMovement(XMotionEvent* event) = 0;
+
+ // Called when the mouse button is released.
+ virtual void OnMouseReleased() = 0;
+
+ // Called when the user has released the mouse button. The move loop will
+ // release the grab after this has been called.
+ virtual void OnMoveLoopEnded() = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_DELEGATE_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
new file mode 100644
index 00000000000..3495b04bc58
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
+
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+#include "base/message_loop/message_pump_aurax11.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/base/events/event.h"
+#include "ui/base/events/event_utils.h"
+#include "ui/base/hit_test.h"
+#include "ui/views/widget/desktop_aura/desktop_activation_client.h"
+#include "ui/views/widget/native_widget_aura.h"
+
+namespace {
+
+// These constants are defined in the Extended Window Manager Hints
+// standard...and aren't in any header that I can find.
+const int k_NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
+const int k_NET_WM_MOVERESIZE_SIZE_TOP = 1;
+const int k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2;
+const int k_NET_WM_MOVERESIZE_SIZE_RIGHT = 3;
+const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4;
+const int k_NET_WM_MOVERESIZE_SIZE_BOTTOM = 5;
+const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
+const int k_NET_WM_MOVERESIZE_SIZE_LEFT = 7;
+const int k_NET_WM_MOVERESIZE_MOVE = 8;
+
+// This data structure represents additional hints that we send to the window
+// manager and has a direct lineage back to Motif, which defined this de facto
+// standard. This struct doesn't seem 64-bit safe though, but it's what GDK
+// does.
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long input_mode;
+ unsigned long status;
+} MotifWmHints;
+
+// The bitflag in |flags| in MotifWmHints that signals that the reader should
+// pay attention to the value in |decorations|.
+const unsigned long kHintsDecorations = (1L << 1);
+
+const char* kAtomsToCache[] = {
+ "_MOTIF_WM_HINTS",
+ "_NET_WM_MOVERESIZE",
+ NULL
+};
+
+} // namespace
+
+namespace views {
+
+X11WindowEventFilter::X11WindowEventFilter(
+ aura::RootWindow* root_window,
+ DesktopActivationClient* activation_client)
+ : activation_client_(activation_client),
+ xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
+ xwindow_(root_window->GetAcceleratedWidget()),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ atom_cache_(xdisplay_, kAtomsToCache),
+ is_active_(false) {
+}
+
+X11WindowEventFilter::~X11WindowEventFilter() {
+}
+
+void X11WindowEventFilter::SetUseHostWindowBorders(bool use_os_border) {
+ MotifWmHints motif_hints;
+ memset(&motif_hints, 0, sizeof(motif_hints));
+ motif_hints.flags = kHintsDecorations;
+ motif_hints.decorations = use_os_border ? 1 : 0;
+
+ ::Atom hint_atom = atom_cache_.GetAtom("_MOTIF_WM_HINTS");
+ XChangeProperty(base::MessagePumpAuraX11::GetDefaultXDisplay(),
+ xwindow_,
+ hint_atom,
+ hint_atom,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&motif_hints),
+ sizeof(MotifWmHints)/sizeof(long));
+}
+
+void X11WindowEventFilter::OnMouseEvent(ui::MouseEvent* event) {
+ if (event->type() != ui::ET_MOUSE_PRESSED)
+ return;
+
+ if (!event->IsLeftMouseButton())
+ return;
+
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ int component =
+ target->delegate()->GetNonClientComponent(event->location());
+ if (component == HTCLIENT)
+ return;
+
+ // Get the |x_root_window_| location out of the native event.
+ if (event->native_event()) {
+ const gfx::Point x_root_location =
+ ui::EventSystemLocationFromNative(event->native_event());
+ if (DispatchHostWindowDragMovement(component, x_root_location))
+ event->StopPropagation();
+ }
+}
+
+bool X11WindowEventFilter::DispatchHostWindowDragMovement(
+ int hittest,
+ const gfx::Point& screen_location) {
+ int direction = -1;
+ switch (hittest) {
+ case HTBOTTOM:
+ direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOM;
+ break;
+ case HTBOTTOMLEFT:
+ direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
+ break;
+ case HTBOTTOMRIGHT:
+ direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
+ break;
+ case HTCAPTION:
+ direction = k_NET_WM_MOVERESIZE_MOVE;
+ break;
+ case HTLEFT:
+ direction = k_NET_WM_MOVERESIZE_SIZE_LEFT;
+ break;
+ case HTRIGHT:
+ direction = k_NET_WM_MOVERESIZE_SIZE_RIGHT;
+ break;
+ case HTTOP:
+ direction = k_NET_WM_MOVERESIZE_SIZE_TOP;
+ break;
+ case HTTOPLEFT:
+ direction = k_NET_WM_MOVERESIZE_SIZE_TOPLEFT;
+ break;
+ case HTTOPRIGHT:
+ direction = k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
+ break;
+ default:
+ return false;
+ }
+
+ // We most likely have an implicit grab right here. We need to dump it
+ // because what we're about to do is tell the window manager
+ // that it's now responsible for moving the window around; it immediately
+ // grabs when it receives the event below.
+ XUngrabPointer(xdisplay_, CurrentTime);
+
+ XEvent event;
+ memset(&event, 0, sizeof(event));
+ event.xclient.type = ClientMessage;
+ event.xclient.display = xdisplay_;
+ event.xclient.window = xwindow_;
+ event.xclient.message_type = atom_cache_.GetAtom("_NET_WM_MOVERESIZE");
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = screen_location.x();
+ event.xclient.data.l[1] = screen_location.y();
+ event.xclient.data.l[2] = direction;
+ event.xclient.data.l[3] = 0;
+ event.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &event);
+
+ return true;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h
new file mode 100644
index 00000000000..a6bdce8d3c8
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WINDOW_EVENT_FILTER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WINDOW_EVENT_FILTER_H_
+
+#include <X11/Xlib.h>
+// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
+#undef RootWindow
+
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/base/events/event_handler.h"
+#include "ui/base/x/x11_atom_cache.h"
+#include "ui/views/views_export.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+}
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+class DesktopActivationClient;
+class NativeWidgetAura;
+
+// An EventFilter that sets properties on X11 windows.
+class VIEWS_EXPORT X11WindowEventFilter : public ui::EventHandler {
+ public:
+ explicit X11WindowEventFilter(aura::RootWindow* root_window,
+ DesktopActivationClient* activation_client);
+ virtual ~X11WindowEventFilter();
+
+ // Changes whether borders are shown on this |root_window|.
+ void SetUseHostWindowBorders(bool use_os_border);
+
+ // Overridden from ui::EventHandler:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+
+ private:
+ // Dispatches a _NET_WM_MOVERESIZE message to the window manager to tell it
+ // to act as if a border or titlebar drag occurred.
+ bool DispatchHostWindowDragMovement(int hittest,
+ const gfx::Point& screen_location);
+
+ DesktopActivationClient* activation_client_;
+
+ // The display and the native X window hosting the root window.
+ Display* xdisplay_;
+ ::Window xwindow_;
+
+ // The native root window.
+ ::Window x_root_window_;
+
+ ui::X11AtomCache atom_cache_;
+
+ // True if |xwindow_| is the current _NET_ACTIVE_WINDOW.
+ bool is_active_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11WindowEventFilter);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WINDOW_EVENT_FILTER_H_
diff --git a/chromium/ui/views/widget/drop_helper.cc b/chromium/ui/views/widget/drop_helper.cc
new file mode 100644
index 00000000000..e4493a30b48
--- /dev/null
+++ b/chromium/ui/views/widget/drop_helper.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/drop_helper.h"
+
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+DropHelper::DropHelper(View* root_view)
+ : root_view_(root_view),
+ target_view_(NULL),
+ deepest_view_(NULL) {
+}
+
+DropHelper::~DropHelper() {
+}
+
+void DropHelper::ResetTargetViewIfEquals(View* view) {
+ if (target_view_ == view)
+ target_view_ = NULL;
+ if (deepest_view_ == view)
+ deepest_view_ = NULL;
+}
+
+int DropHelper::OnDragOver(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation) {
+ View* view = CalculateTargetViewImpl(root_view_location, data, true,
+ &deepest_view_);
+
+ if (view != target_view_) {
+ // Target changed notify old drag exited, then new drag entered.
+ NotifyDragExit();
+ target_view_ = view;
+ NotifyDragEntered(data, root_view_location, drag_operation);
+ }
+
+ return NotifyDragOver(data, root_view_location, drag_operation);
+}
+
+void DropHelper::OnDragExit() {
+ NotifyDragExit();
+ deepest_view_ = target_view_ = NULL;
+}
+
+int DropHelper::OnDrop(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation) {
+ View* drop_view = target_view_;
+ deepest_view_ = target_view_ = NULL;
+ if (!drop_view)
+ return ui::DragDropTypes::DRAG_NONE;
+
+ if (drag_operation == ui::DragDropTypes::DRAG_NONE) {
+ drop_view->OnDragExited();
+ return ui::DragDropTypes::DRAG_NONE;
+ }
+
+ gfx::Point view_location(root_view_location);
+ View* root_view = drop_view->GetWidget()->GetRootView();
+ View::ConvertPointToTarget(root_view, drop_view, &view_location);
+ ui::DropTargetEvent drop_event(data, view_location, view_location,
+ drag_operation);
+ return drop_view->OnPerformDrop(drop_event);
+}
+
+View* DropHelper::CalculateTargetView(
+ const gfx::Point& root_view_location,
+ const OSExchangeData& data,
+ bool check_can_drop) {
+ return CalculateTargetViewImpl(root_view_location, data, check_can_drop,
+ NULL);
+}
+
+View* DropHelper::CalculateTargetViewImpl(
+ const gfx::Point& root_view_location,
+ const OSExchangeData& data,
+ bool check_can_drop,
+ View** deepest_view) {
+ View* view = root_view_->GetEventHandlerForPoint(root_view_location);
+ if (view == deepest_view_) {
+ // The view the mouse is over hasn't changed; reuse the target.
+ return target_view_;
+ }
+ if (deepest_view)
+ *deepest_view = view;
+ // TODO(sky): for the time being these are separate. Once I port chrome menu
+ // I can switch to the #else implementation and nuke the OS_WIN
+ // implementation.
+#if defined(OS_WIN)
+ // View under mouse changed, which means a new view may want the drop.
+ // Walk the tree, stopping at target_view_ as we know it'll accept the
+ // drop.
+ while (view && view != target_view_ &&
+ (!view->enabled() || !view->CanDrop(data))) {
+ view = view->parent();
+ }
+#elif !defined(OS_MACOSX)
+ int formats = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+ while (view && view != target_view_) {
+ if (view->enabled() &&
+ view->GetDropFormats(&formats, &custom_formats) &&
+ data.HasAnyFormat(formats, custom_formats) &&
+ (!check_can_drop || view->CanDrop(data))) {
+ // Found the view.
+ return view;
+ }
+ formats = 0;
+ custom_formats.clear();
+ view = view->parent();
+ }
+#endif
+ return view;
+}
+
+void DropHelper::NotifyDragEntered(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation) {
+ if (!target_view_)
+ return;
+
+ gfx::Point target_view_location(root_view_location);
+ View::ConvertPointToTarget(root_view_, target_view_, &target_view_location);
+ ui::DropTargetEvent enter_event(data,
+ target_view_location,
+ target_view_location,
+ drag_operation);
+ target_view_->OnDragEntered(enter_event);
+}
+
+int DropHelper::NotifyDragOver(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation) {
+ if (!target_view_)
+ return ui::DragDropTypes::DRAG_NONE;
+
+ gfx::Point target_view_location(root_view_location);
+ View::ConvertPointToTarget(root_view_, target_view_, &target_view_location);
+ ui::DropTargetEvent enter_event(data,
+ target_view_location,
+ target_view_location,
+ drag_operation);
+ return target_view_->OnDragUpdated(enter_event);
+}
+
+void DropHelper::NotifyDragExit() {
+ if (target_view_)
+ target_view_->OnDragExited();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/drop_helper.h b/chromium/ui/views/widget/drop_helper.h
new file mode 100644
index 00000000000..9247e1e7d32
--- /dev/null
+++ b/chromium/ui/views/widget/drop_helper.h
@@ -0,0 +1,107 @@
+// 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_VIEWS_WIDGET_DROP_HELPER_H_
+#define UI_VIEWS_WIDGET_DROP_HELPER_H_
+
+#include "base/basictypes.h"
+
+namespace gfx {
+class Point;
+} // namespace gfx
+
+namespace ui {
+class OSExchangeData;
+} // namespace ui
+using ui::OSExchangeData;
+
+namespace views {
+
+class RootView;
+class View;
+
+// DropHelper provides support for managing the view a drop is going to occur
+// at during dnd as well as sending the view the appropriate dnd methods.
+// DropHelper is intended to be used by a class that interacts with the system
+// drag and drop. The system class invokes OnDragOver as the mouse moves,
+// then either OnDragExit or OnDrop when the drop is done.
+class DropHelper {
+ public:
+ explicit DropHelper(View* root_view);
+ ~DropHelper();
+
+ // Current view drop events are targeted at, may be NULL.
+ View* target_view() const { return target_view_; }
+
+ // Returns the RootView the DropHelper was created with.
+ View* root_view() const { return root_view_; }
+
+ // Resets the target_view_ to NULL if it equals view.
+ //
+ // This is invoked when a View is removed from the RootView to make sure
+ // we don't target a view that was removed during dnd.
+ void ResetTargetViewIfEquals(View* view);
+
+ // Invoked when a the mouse is dragged over the root view during a drag and
+ // drop operation. This method returns a bitmask of the types in DragDropTypes
+ // for the target view. If no view wants the drop, DRAG_NONE is returned.
+ int OnDragOver(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation);
+
+ // Invoked when a the mouse is dragged out of the root view during a drag and
+ // drop operation.
+ void OnDragExit();
+
+ // Invoked when the user drops data on the root view during a drag and drop
+ // operation. See OnDragOver for details on return type.
+ //
+ // NOTE: implementations must invoke OnDragOver before invoking this,
+ // supplying the return value from OnDragOver as the drag_operation.
+ int OnDrop(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation);
+
+ // Calculates the target view for a drop given the specified location in
+ // the coordinate system of the rootview. This tries to avoid continually
+ // querying CanDrop by returning target_view_ if the mouse is still over
+ // target_view_.
+ View* CalculateTargetView(const gfx::Point& root_view_location,
+ const OSExchangeData& data,
+ bool check_can_drop);
+
+ private:
+ // Implementation of CalculateTargetView. If |deepest_view| is non-NULL it is
+ // set to the deepest descendant of the RootView that contains the point
+ // |root_view_location|
+ View* CalculateTargetViewImpl(const gfx::Point& root_view_location,
+ const OSExchangeData& data,
+ bool check_can_drop,
+ View** deepest_view);
+
+ // Methods to send the appropriate drop notification to the targeted view.
+ // These do nothing if the target view is NULL.
+ void NotifyDragEntered(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation);
+ int NotifyDragOver(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation);
+ void NotifyDragExit();
+
+ // RootView we were created for.
+ View* root_view_;
+
+ // View we're targeting events at.
+ View* target_view_;
+
+ // The deepest view under the current drop coordinate.
+ View* deepest_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropHelper);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DROP_HELPER_H_
diff --git a/chromium/ui/views/widget/drop_target_win.cc b/chromium/ui/views/widget/drop_target_win.cc
new file mode 100644
index 00000000000..dfe15f9af23
--- /dev/null
+++ b/chromium/ui/views/widget/drop_target_win.cc
@@ -0,0 +1,63 @@
+// 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/views/widget/drop_target_win.h"
+
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
+#include "ui/gfx/point.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget.h"
+
+using ui::OSExchangeData;
+using ui::OSExchangeDataProviderWin;
+
+namespace views {
+
+DropTargetWin::DropTargetWin(internal::RootView* root_view)
+ : ui::DropTargetWin(root_view->GetWidget()->GetNativeView()),
+ helper_(root_view) {
+}
+
+DropTargetWin::~DropTargetWin() {
+}
+
+void DropTargetWin::ResetTargetViewIfEquals(View* view) {
+ helper_.ResetTargetViewIfEquals(view);
+}
+
+DWORD DropTargetWin::OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ gfx::Point root_view_location(cursor_position.x, cursor_position.y);
+ View::ConvertPointToTarget(NULL, helper_.root_view(), &root_view_location);
+ OSExchangeData data(new OSExchangeDataProviderWin(data_object));
+ int drop_operation =
+ helper_.OnDragOver(data, root_view_location,
+ ui::DragDropTypes::DropEffectToDragOperation(effect));
+ return ui::DragDropTypes::DragOperationToDropEffect(drop_operation);
+}
+
+void DropTargetWin::OnDragLeave(IDataObject* data_object) {
+ helper_.OnDragExit();
+}
+
+DWORD DropTargetWin::OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ gfx::Point root_view_location(cursor_position.x, cursor_position.y);
+ View::ConvertPointToTarget(NULL, helper_.root_view(), &root_view_location);
+
+ OSExchangeData data(new OSExchangeDataProviderWin(data_object));
+ int drop_operation = ui::DragDropTypes::DropEffectToDragOperation(effect);
+ drop_operation = helper_.OnDragOver(data, root_view_location,
+ drop_operation);
+ drop_operation = helper_.OnDrop(data, root_view_location, drop_operation);
+ return ui::DragDropTypes::DragOperationToDropEffect(drop_operation);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/drop_target_win.h b/chromium/ui/views/widget/drop_target_win.h
new file mode 100644
index 00000000000..742675122df
--- /dev/null
+++ b/chromium/ui/views/widget/drop_target_win.h
@@ -0,0 +1,55 @@
+// 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_VIEWS_WIDGET_DROP_TARGET_WIN_H_
+#define UI_VIEWS_WIDGET_DROP_TARGET_WIN_H_
+
+#include "ui/base/dragdrop/drop_target_win.h"
+#include "ui/views/widget/drop_helper.h"
+
+namespace views {
+
+class View;
+namespace internal {
+class RootView;
+}
+
+// DropTargetWin takes care of managing drag and drop for NativeWidgetWin. It
+// converts Windows OLE drop messages into Views drop messages.
+//
+// DropTargetWin uses DropHelper to manage the appropriate view to target
+// drop messages at.
+class DropTargetWin : public ui::DropTargetWin {
+ public:
+ explicit DropTargetWin(internal::RootView* root_view);
+ virtual ~DropTargetWin();
+
+ // If a drag and drop is underway and view is the current drop target, the
+ // drop target is set to null.
+ // This is invoked when a View is removed from the RootView to make sure
+ // we don't target a view that was removed during dnd.
+ void ResetTargetViewIfEquals(View* view);
+
+ protected:
+ virtual DWORD OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ virtual void OnDragLeave(IDataObject* data_object);
+
+ virtual DWORD OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ private:
+ views::DropHelper helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropTargetWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DROP_TARGET_WIN_H_
diff --git a/chromium/ui/views/widget/monitor_win.cc b/chromium/ui/views/widget/monitor_win.cc
new file mode 100644
index 00000000000..c183cb0f6db
--- /dev/null
+++ b/chromium/ui/views/widget/monitor_win.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/monitor_win.h"
+
+#include <shellapi.h>
+
+#include "base/logging.h"
+#include "ui/gfx/rect.h"
+
+namespace views {
+
+gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect) {
+ RECT p_rect = rect.ToRECT();
+ HMONITOR monitor = MonitorFromRect(&p_rect, MONITOR_DEFAULTTONEAREST);
+ if (monitor) {
+ MONITORINFO mi = {0};
+ mi.cbSize = sizeof(mi);
+ GetMonitorInfo(monitor, &mi);
+ return gfx::Rect(mi.rcWork);
+ }
+ NOTREACHED();
+ return gfx::Rect();
+}
+
+HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor) {
+ // NOTE: this may be invoked on a background thread.
+ APPBARDATA taskbar_data = { sizeof(APPBARDATA), NULL, 0, edge };
+ HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR,
+ &taskbar_data));
+ return (::IsWindow(taskbar) && (monitor != NULL) &&
+ (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) &&
+ (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST)) ?
+ taskbar : NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/monitor_win.h b/chromium/ui/views/widget/monitor_win.h
new file mode 100644
index 00000000000..87bdc4e00c2
--- /dev/null
+++ b/chromium/ui/views/widget/monitor_win.h
@@ -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.
+
+#ifndef UI_VIEWS_WIDGET_MONITOR_WIN_H_
+#define UI_VIEWS_WIDGET_MONITOR_WIN_H_
+
+#include <windows.h>
+
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+// Returns the bounds for the monitor that contains the largest area of
+// intersection with the specified rectangle.
+VIEWS_EXPORT gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect);
+
+// Returns the always-on-top auto-hiding taskbar for edge |edge| (one of
+// ABE_LEFT, TOP, RIGHT, or BOTTOM) of monitor |monitor|. NULL is returned
+// if nothing is found.
+//
+// WARNING: this function spawns a nested message loop. Use Appbar instead if
+// possible.
+VIEWS_EXPORT HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor);
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_MONITOR_WIN_H_
diff --git a/chromium/ui/views/widget/native_widget.h b/chromium/ui/views/widget/native_widget.h
new file mode 100644
index 00000000000..39255ffc9c1
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget.h
@@ -0,0 +1,44 @@
+// 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_VIEWS_WIDGET_NATIVE_WIDGET_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_H_
+
+#include "ui/views/widget/widget.h"
+
+namespace ui {
+class EventHandler;
+}
+
+namespace views {
+namespace internal {
+class NativeWidgetPrivate;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidget interface
+//
+// An interface that serves as the public API base for the
+// internal::NativeWidget interface that Widget uses to communicate with a
+// backend-specific native widget implementation. This is the only component of
+// this interface that is publicly visible, and exists solely for exposure via
+// Widget's native_widget() accessor, which code occasionally static_casts to
+// a known implementation in platform-specific code.
+//
+class VIEWS_EXPORT NativeWidget {
+ public:
+ virtual ~NativeWidget() {}
+
+ // Retrieves the event handler
+ virtual ui::EventHandler* GetEventHandler() = 0;
+
+ private:
+ friend class Widget;
+
+ virtual internal::NativeWidgetPrivate* AsNativeWidgetPrivate() = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_H_
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
new file mode 100644
index 00000000000..8c9ad02b899
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -0,0 +1,1078 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/native_widget_aura.h"
+
+#include "base/bind.h"
+#include "base/strings/string_util.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/aura/client/activation_client.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/client/stacking_client.h"
+#include "ui/aura/client/window_move_client.h"
+#include "ui/aura/client/window_types.h"
+#include "ui/aura/env.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/events/event.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/screen.h"
+#include "ui/native_theme/native_theme_aura.h"
+#include "ui/views/drag_utils.h"
+#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/drop_helper.h"
+#include "ui/views/widget/native_widget_aura_window_observer.h"
+#include "ui/views/widget/native_widget_delegate.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/tooltip_manager_aura.h"
+#include "ui/views/widget/widget_aura_utils.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/window_reorderer.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/win_util.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
+#endif
+
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+#endif
+
+#if !defined(OS_CHROMEOS)
+#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+#endif
+
+namespace views {
+
+namespace {
+
+void SetRestoreBounds(aura::Window* window, const gfx::Rect& bounds) {
+ window->SetProperty(aura::client::kRestoreBoundsKey, new gfx::Rect(bounds));
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, public:
+
+NativeWidgetAura::NativeWidgetAura(internal::NativeWidgetDelegate* delegate)
+ : delegate_(delegate),
+ window_(new aura::Window(this)),
+ ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
+ close_widget_factory_(this),
+ can_activate_(true),
+ destroying_(false),
+ cursor_(gfx::kNullCursor),
+ saved_window_state_(ui::SHOW_STATE_DEFAULT) {
+ aura::client::SetFocusChangeObserver(window_, this);
+ aura::client::SetActivationChangeObserver(window_, this);
+}
+
+// static
+gfx::Font NativeWidgetAura::GetWindowTitleFont() {
+#if defined(OS_WIN)
+ NONCLIENTMETRICS ncm;
+ base::win::GetNonClientMetrics(&ncm);
+ l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
+ base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
+ return gfx::Font(caption_font);
+#else
+ return gfx::Font();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, internal::NativeWidgetPrivate implementation:
+
+void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
+ // Aura needs to know which desktop (Ash or regular) will manage this widget.
+ // See Widget::InitParams::context for details.
+ DCHECK(params.parent || params.context);
+
+ ownership_ = params.ownership;
+
+ window_->set_user_data(this);
+ window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
+ window_->SetProperty(aura::client::kShowStateKey, params.show_state);
+ if (params.type == Widget::InitParams::TYPE_BUBBLE)
+ aura::client::SetHideOnDeactivate(window_, true);
+ window_->SetTransparent(
+ params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW);
+ window_->Init(params.layer_type);
+ if (params.type == Widget::InitParams::TYPE_CONTROL)
+ window_->Show();
+
+ delegate_->OnNativeWidgetCreated(false);
+
+ gfx::Rect window_bounds = params.bounds;
+ gfx::NativeView parent = params.parent;
+ gfx::NativeView context = params.context;
+ if (!params.child) {
+ // Set up the transient child before the window is added. This way the
+ // LayoutManager knows the window has a transient parent.
+ if (parent && parent->type() != aura::client::WINDOW_TYPE_UNKNOWN) {
+ parent->AddTransientChild(window_);
+ if (!context)
+ context = parent;
+ parent = NULL;
+ }
+ // SetAlwaysOnTop before SetParent so that always-on-top container is used.
+ SetAlwaysOnTop(params.keep_on_top);
+ // Make sure we have a real |window_bounds|.
+ if (parent && window_bounds == gfx::Rect()) {
+ // If a parent is specified but no bounds are given,
+ // use the origin of the parent's display so that the widget
+ // will be added to the same display as the parent.
+ gfx::Rect bounds = gfx::Screen::GetScreenFor(parent)->
+ GetDisplayNearestWindow(parent).bounds();
+ window_bounds.set_origin(bounds.origin());
+ }
+ }
+
+ if (parent) {
+ parent->AddChild(window_);
+ } else {
+ window_->SetDefaultParentByRootWindow(context->GetRootWindow(),
+ window_bounds);
+ }
+
+ // Wait to set the bounds until we have a parent. That way we can know our
+ // true state/bounds (the LayoutManager may enforce a particular
+ // state/bounds).
+ if (IsMaximized())
+ SetRestoreBounds(window_, window_bounds);
+ else
+ SetBounds(window_bounds);
+ window_->set_ignore_events(!params.accept_events);
+ can_activate_ = params.can_activate &&
+ params.type != Widget::InitParams::TYPE_CONTROL &&
+ params.type != Widget::InitParams::TYPE_TOOLTIP;
+ DCHECK(GetWidget()->GetRootView());
+#if !defined(OS_MACOSX)
+ if (params.type != Widget::InitParams::TYPE_TOOLTIP)
+ tooltip_manager_.reset(new views::TooltipManagerAura(window_, GetWidget()));
+#endif // !defined(OS_MACOSX)
+
+ drop_helper_.reset(new DropHelper(GetWidget()->GetRootView()));
+ if (params.type != Widget::InitParams::TYPE_TOOLTIP &&
+ params.type != Widget::InitParams::TYPE_POPUP) {
+ aura::client::SetDragDropDelegate(window_, this);
+ }
+
+ aura::client::SetActivationDelegate(window_, this);
+
+ window_->SetProperty(aura::client::kCanMaximizeKey,
+ GetWidget()->widget_delegate()->CanMaximize());
+ window_->SetProperty(aura::client::kCanResizeKey,
+ GetWidget()->widget_delegate()->CanResize());
+
+ window_reorderer_.reset(new WindowReorderer(window_,
+ GetWidget()->GetRootView()));
+}
+
+NonClientFrameView* NativeWidgetAura::CreateNonClientFrameView() {
+ return NULL;
+}
+
+bool NativeWidgetAura::ShouldUseNativeFrame() const {
+ // There is only one frame type for aura.
+ return false;
+}
+
+void NativeWidgetAura::FrameTypeChanged() {
+ // This is called when the Theme has changed; forward the event to the root
+ // widget.
+ GetWidget()->ThemeChanged();
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+Widget* NativeWidgetAura::GetWidget() {
+ return delegate_->AsWidget();
+}
+
+const Widget* NativeWidgetAura::GetWidget() const {
+ return delegate_->AsWidget();
+}
+
+gfx::NativeView NativeWidgetAura::GetNativeView() const {
+ return window_;
+}
+
+gfx::NativeWindow NativeWidgetAura::GetNativeWindow() const {
+ return window_;
+}
+
+Widget* NativeWidgetAura::GetTopLevelWidget() {
+ NativeWidgetPrivate* native_widget = GetTopLevelNativeWidget(GetNativeView());
+ return native_widget ? native_widget->GetWidget() : NULL;
+}
+
+const ui::Compositor* NativeWidgetAura::GetCompositor() const {
+ return window_->layer()->GetCompositor();
+}
+
+ui::Compositor* NativeWidgetAura::GetCompositor() {
+ return window_->layer()->GetCompositor();
+}
+
+ui::Layer* NativeWidgetAura::GetLayer() {
+ return window_->layer();
+}
+
+void NativeWidgetAura::ReorderNativeViews() {
+ window_reorderer_->ReorderChildWindows();
+}
+
+void NativeWidgetAura::ViewRemoved(View* view) {
+ DCHECK(drop_helper_.get() != NULL);
+ drop_helper_->ResetTargetViewIfEquals(view);
+}
+
+void NativeWidgetAura::SetNativeWindowProperty(const char* name, void* value) {
+ if (window_)
+ window_->SetNativeWindowProperty(name, value);
+}
+
+void* NativeWidgetAura::GetNativeWindowProperty(const char* name) const {
+ return window_ ? window_->GetNativeWindowProperty(name) : NULL;
+}
+
+TooltipManager* NativeWidgetAura::GetTooltipManager() const {
+ return tooltip_manager_.get();
+}
+
+void NativeWidgetAura::SetCapture() {
+ window_->SetCapture();
+}
+
+void NativeWidgetAura::ReleaseCapture() {
+ window_->ReleaseCapture();
+}
+
+bool NativeWidgetAura::HasCapture() const {
+ return window_->HasCapture();
+}
+
+InputMethod* NativeWidgetAura::CreateInputMethod() {
+ aura::RootWindow* root_window = window_->GetRootWindow();
+ ui::InputMethod* host =
+ root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+ return new InputMethodBridge(this, host, true);
+}
+
+internal::InputMethodDelegate* NativeWidgetAura::GetInputMethodDelegate() {
+ return this;
+}
+
+void NativeWidgetAura::CenterWindow(const gfx::Size& size) {
+ gfx::Rect parent_bounds(window_->parent()->GetBoundsInRootWindow());
+ // When centering window, we take the intersection of the host and
+ // the parent. We assume the root window represents the visible
+ // rect of a single screen.
+ gfx::Rect work_area = gfx::Screen::GetScreenFor(window_)->
+ GetDisplayNearestWindow(window_).work_area();
+
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window_->GetRootWindow());
+ if (screen_position_client) {
+ gfx::Point origin = work_area.origin();
+ screen_position_client->ConvertPointFromScreen(window_->GetRootWindow(),
+ &origin);
+ work_area.set_origin(origin);
+ }
+
+ parent_bounds.Intersect(work_area);
+
+ // If |window_|'s transient parent's bounds are big enough to fit it, then we
+ // center it with respect to the transient parent.
+ if (window_->transient_parent()) {
+ gfx::Rect transient_parent_rect = window_->transient_parent()->
+ GetBoundsInRootWindow();
+ transient_parent_rect.Intersect(work_area);
+ if (transient_parent_rect.height() >= size.height() &&
+ transient_parent_rect.width() >= size.width())
+ parent_bounds = transient_parent_rect;
+ }
+
+ gfx::Rect window_bounds(
+ parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
+ parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
+ size.width(),
+ size.height());
+ // Don't size the window bigger than the parent, otherwise the user may not be
+ // able to close or move it.
+ window_bounds.AdjustToFit(parent_bounds);
+
+ // Convert the bounds back relative to the parent.
+ gfx::Point origin = window_bounds.origin();
+ aura::Window::ConvertPointToTarget(window_->GetRootWindow(),
+ window_->parent(), &origin);
+ window_bounds.set_origin(origin);
+ window_->SetBounds(window_bounds);
+}
+
+void NativeWidgetAura::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ // The interface specifies returning restored bounds, not current bounds.
+ *bounds = GetRestoredBounds();
+ *show_state = window_->GetProperty(aura::client::kShowStateKey);
+}
+
+void NativeWidgetAura::SetWindowTitle(const string16& title) {
+ window_->set_title(title);
+}
+
+void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) {
+ // Aura doesn't have window icons.
+}
+
+void NativeWidgetAura::InitModalType(ui::ModalType modal_type) {
+ if (modal_type != ui::MODAL_TYPE_NONE)
+ window_->SetProperty(aura::client::kModalKey, modal_type);
+}
+
+gfx::Rect NativeWidgetAura::GetWindowBoundsInScreen() const {
+ return window_->GetBoundsInScreen();
+}
+
+gfx::Rect NativeWidgetAura::GetClientAreaBoundsInScreen() const {
+ // View-to-screen coordinate system transformations depend on this returning
+ // the full window bounds, for example View::ConvertPointToScreen().
+ return window_->GetBoundsInScreen();
+}
+
+gfx::Rect NativeWidgetAura::GetRestoredBounds() const {
+ // Restored bounds should only be relevant if the window is minimized or
+ // maximized. However, in some places the code expects GetRestoredBounds()
+ // to return the current window bounds if the window is not in either state.
+ if (IsMinimized() || IsMaximized() || IsFullscreen()) {
+ // Restore bounds are in screen coordinates, no need to convert.
+ gfx::Rect* restore_bounds =
+ window_->GetProperty(aura::client::kRestoreBoundsKey);
+ if (restore_bounds)
+ return *restore_bounds;
+ }
+ return window_->GetBoundsInScreen();
+}
+
+void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
+ aura::RootWindow* root = window_->GetRootWindow();
+ if (root) {
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(root);
+ if (screen_position_client) {
+ gfx::Display dst_display =
+ gfx::Screen::GetScreenFor(window_)->GetDisplayMatching(bounds);
+ screen_position_client->SetBounds(window_, bounds, dst_display);
+ return;
+ }
+ }
+ window_->SetBounds(bounds);
+}
+
+void NativeWidgetAura::SetSize(const gfx::Size& size) {
+ window_->SetBounds(gfx::Rect(window_->bounds().origin(), size));
+}
+
+void NativeWidgetAura::StackAbove(gfx::NativeView native_view) {
+ if (window_->parent() && window_->parent() == native_view->parent())
+ window_->parent()->StackChildAbove(window_, native_view);
+}
+
+void NativeWidgetAura::StackAtTop() {
+ window_->parent()->StackChildAtTop(window_);
+}
+
+void NativeWidgetAura::StackBelow(gfx::NativeView native_view) {
+ if (window_->parent() && window_->parent() == native_view->parent())
+ window_->parent()->StackChildBelow(window_, native_view);
+}
+
+void NativeWidgetAura::SetShape(gfx::NativeRegion region) {
+ // No need for this. Just delete and ignore.
+ delete region;
+}
+
+void NativeWidgetAura::Close() {
+ // |window_| may already be deleted by parent window. This can happen
+ // when this widget is child widget or has transient parent
+ // and ownership is WIDGET_OWNS_NATIVE_WIDGET.
+ DCHECK(window_ ||
+ ownership_ == Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
+ if (window_) {
+ window_->SuppressPaint();
+ Hide();
+ window_->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
+ }
+
+ if (!close_widget_factory_.HasWeakPtrs()) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&NativeWidgetAura::CloseNow,
+ close_widget_factory_.GetWeakPtr()));
+ }
+}
+
+void NativeWidgetAura::CloseNow() {
+ delete window_;
+}
+
+void NativeWidgetAura::Show() {
+ ShowWithWindowState(ui::SHOW_STATE_INACTIVE);
+}
+
+void NativeWidgetAura::Hide() {
+ window_->Hide();
+}
+
+void NativeWidgetAura::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ SetRestoreBounds(window_, restored_bounds);
+ ShowWithWindowState(ui::SHOW_STATE_MAXIMIZED);
+}
+
+void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
+ if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN)
+ window_->SetProperty(aura::client::kShowStateKey, state);
+ window_->Show();
+ if (can_activate_) {
+ if (state != ui::SHOW_STATE_INACTIVE)
+ Activate();
+ // SetInitialFocus() should be always be called, even for
+ // SHOW_STATE_INACTIVE. When a frameless modal dialog is created by
+ // a widget of TYPE_WINDOW_FRAMELESS, Widget::Show() will call into
+ // this function with the window state SHOW_STATE_INACTIVE,
+ // SetInitialFoucs() has to be called so that the dialog can get focus.
+ // This also matches NativeWidgetWin which invokes SetInitialFocus
+ // regardless of show state.
+ SetInitialFocus();
+ }
+}
+
+bool NativeWidgetAura::IsVisible() const {
+ return window_->IsVisible();
+}
+
+void NativeWidgetAura::Activate() {
+ // We don't necessarily have a root window yet. This can happen with
+ // constrained windows.
+ if (window_->GetRootWindow()) {
+ aura::client::GetActivationClient(window_->GetRootWindow())->ActivateWindow(
+ window_);
+ }
+ if (window_->GetProperty(aura::client::kDrawAttentionKey))
+ window_->SetProperty(aura::client::kDrawAttentionKey, false);
+}
+
+void NativeWidgetAura::Deactivate() {
+ aura::client::GetActivationClient(window_->GetRootWindow())->DeactivateWindow(
+ window_);
+}
+
+bool NativeWidgetAura::IsActive() const {
+ return aura::client::GetActivationClient(window_->GetRootWindow())->
+ GetActiveWindow() == window_;
+}
+
+void NativeWidgetAura::SetAlwaysOnTop(bool on_top) {
+ window_->SetProperty(aura::client::kAlwaysOnTopKey, on_top);
+}
+
+void NativeWidgetAura::Maximize() {
+ window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+}
+
+void NativeWidgetAura::Minimize() {
+ window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
+}
+
+bool NativeWidgetAura::IsMaximized() const {
+ return window_->GetProperty(aura::client::kShowStateKey) ==
+ ui::SHOW_STATE_MAXIMIZED;
+}
+
+bool NativeWidgetAura::IsMinimized() const {
+ return window_->GetProperty(aura::client::kShowStateKey) ==
+ ui::SHOW_STATE_MINIMIZED;
+}
+
+void NativeWidgetAura::Restore() {
+ window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+}
+
+void NativeWidgetAura::SetFullscreen(bool fullscreen) {
+ if (IsFullscreen() == fullscreen)
+ return; // Nothing to do.
+
+ // Save window state before entering full screen so that it could restored
+ // when exiting full screen.
+ if (fullscreen)
+ saved_window_state_ = window_->GetProperty(aura::client::kShowStateKey);
+
+ window_->SetProperty(
+ aura::client::kShowStateKey,
+ fullscreen ? ui::SHOW_STATE_FULLSCREEN : saved_window_state_);
+}
+
+bool NativeWidgetAura::IsFullscreen() const {
+ return window_->GetProperty(aura::client::kShowStateKey) ==
+ ui::SHOW_STATE_FULLSCREEN;
+}
+
+void NativeWidgetAura::SetOpacity(unsigned char opacity) {
+ window_->layer()->SetOpacity(opacity / 255.0);
+}
+
+void NativeWidgetAura::SetUseDragFrame(bool use_drag_frame) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetAura::FlashFrame(bool flash) {
+ window_->SetProperty(aura::client::kDrawAttentionKey, flash);
+}
+
+void NativeWidgetAura::RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ views::RunShellDrag(window_, data, location, operation, source);
+}
+
+void NativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
+ if (window_)
+ window_->SchedulePaintInRect(rect);
+}
+
+void NativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
+ cursor_ = cursor;
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window_->GetRootWindow());
+ if (cursor_client)
+ cursor_client->SetCursor(cursor);
+}
+
+bool NativeWidgetAura::IsMouseEventsEnabled() const {
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window_->GetRootWindow());
+ return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
+}
+
+void NativeWidgetAura::ClearNativeFocus() {
+ aura::client::FocusClient* client = aura::client::GetFocusClient(window_);
+ if (window_ && client && window_->Contains(client->GetFocusedWindow()))
+ client->ResetFocusWithinActiveWindow(window_);
+}
+
+gfx::Rect NativeWidgetAura::GetWorkAreaBoundsInScreen() const {
+ return gfx::Screen::GetScreenFor(GetNativeView())->
+ GetDisplayNearestWindow(GetNativeView()).work_area();
+}
+
+void NativeWidgetAura::SetInactiveRenderingDisabled(bool value) {
+ if (!value) {
+ active_window_observer_.reset();
+ } else {
+ active_window_observer_.reset(
+ new NativeWidgetAuraWindowObserver(window_, delegate_));
+ }
+}
+
+Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) {
+ if (window_->parent() &&
+ aura::client::GetWindowMoveClient(window_->parent())) {
+ SetCapture();
+ aura::client::WindowMoveSource window_move_source =
+ source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE :
+ aura::client::WINDOW_MOVE_SOURCE_TOUCH;
+ if (aura::client::GetWindowMoveClient(window_->parent())->RunMoveLoop(
+ window_, drag_offset, window_move_source) ==
+ aura::client::MOVE_SUCCESSFUL) {
+ return Widget::MOVE_LOOP_SUCCESSFUL;
+ }
+ }
+ return Widget::MOVE_LOOP_CANCELED;
+}
+
+void NativeWidgetAura::EndMoveLoop() {
+ if (window_->parent() &&
+ aura::client::GetWindowMoveClient(window_->parent())) {
+ aura::client::GetWindowMoveClient(window_->parent())->EndMoveLoop();
+ }
+}
+
+void NativeWidgetAura::SetVisibilityChangedAnimationsEnabled(bool value) {
+ window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
+}
+
+ui::NativeTheme* NativeWidgetAura::GetNativeTheme() const {
+#if !defined(OS_CHROMEOS)
+ return DesktopRootWindowHost::GetNativeTheme(window_);
+#else
+ return ui::NativeThemeAura::instance();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, views::InputMethodDelegate implementation:
+
+void NativeWidgetAura::DispatchKeyEventPostIME(const ui::KeyEvent& key) {
+ FocusManager* focus_manager = GetWidget()->GetFocusManager();
+ delegate_->OnKeyEvent(const_cast<ui::KeyEvent*>(&key));
+ if (key.handled() || !focus_manager)
+ return;
+ focus_manager->OnKeyEvent(key);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, aura::WindowDelegate implementation:
+
+gfx::Size NativeWidgetAura::GetMinimumSize() const {
+ return delegate_->GetMinimumSize();
+}
+
+gfx::Size NativeWidgetAura::GetMaximumSize() const {
+ return delegate_->GetMaximumSize();
+}
+
+void NativeWidgetAura::OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ if (old_bounds.origin() != new_bounds.origin())
+ delegate_->OnNativeWidgetMove();
+ if (old_bounds.size() != new_bounds.size())
+ delegate_->OnNativeWidgetSizeChanged(new_bounds.size());
+}
+
+gfx::NativeCursor NativeWidgetAura::GetCursor(const gfx::Point& point) {
+ return cursor_;
+}
+
+int NativeWidgetAura::GetNonClientComponent(const gfx::Point& point) const {
+ return delegate_->GetNonClientComponent(point);
+}
+
+bool NativeWidgetAura::ShouldDescendIntoChildForEventHandling(
+ aura::Window* child,
+ const gfx::Point& location) {
+ views::WidgetDelegate* widget_delegate = GetWidget()->widget_delegate();
+ if (widget_delegate &&
+ !widget_delegate->ShouldDescendIntoChildForEventHandling(child, location))
+ return false;
+
+ // Don't descend into |child| if there is a view with a Layer that contains
+ // the point and is stacked above |child|s layer.
+ typedef std::vector<ui::Layer*> Layers;
+ const Layers& root_layers(delegate_->GetRootLayers());
+ if (root_layers.empty())
+ return true;
+
+ Layers::const_iterator child_layer_iter(
+ std::find(window_->layer()->children().begin(),
+ window_->layer()->children().end(), child->layer()));
+ if (child_layer_iter == window_->layer()->children().end())
+ return true;
+
+ for (std::vector<ui::Layer*>::const_reverse_iterator i = root_layers.rbegin();
+ i != root_layers.rend(); ++i) {
+ ui::Layer* layer = *i;
+ if (layer->visible() && layer->bounds().Contains(location)) {
+ Layers::const_iterator root_layer_iter(
+ std::find(window_->layer()->children().begin(),
+ window_->layer()->children().end(), layer));
+ if (root_layer_iter > child_layer_iter)
+ return false;
+ }
+ }
+ return true;
+}
+
+bool NativeWidgetAura::CanFocus() {
+ return can_activate_;
+}
+
+void NativeWidgetAura::OnCaptureLost() {
+ delegate_->OnMouseCaptureLost();
+}
+
+void NativeWidgetAura::OnPaint(gfx::Canvas* canvas) {
+ delegate_->OnNativeWidgetPaint(canvas);
+}
+
+void NativeWidgetAura::OnDeviceScaleFactorChanged(float device_scale_factor) {
+ // Repainting with new scale factor will paint the content at the right scale.
+}
+
+void NativeWidgetAura::OnWindowDestroying() {
+ delegate_->OnNativeWidgetDestroying();
+
+ // If the aura::Window is destroyed, we can no longer show tooltips.
+ tooltip_manager_.reset();
+}
+
+void NativeWidgetAura::OnWindowDestroyed() {
+ window_ = NULL;
+ delegate_->OnNativeWidgetDestroyed();
+ if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ delete this;
+}
+
+void NativeWidgetAura::OnWindowTargetVisibilityChanged(bool visible) {
+ delegate_->OnNativeWidgetVisibilityChanged(visible);
+}
+
+bool NativeWidgetAura::HasHitTestMask() const {
+ return delegate_->HasHitTestMask();
+}
+
+void NativeWidgetAura::GetHitTestMask(gfx::Path* mask) const {
+ DCHECK(mask);
+ delegate_->GetHitTestMask(mask);
+}
+
+scoped_refptr<ui::Texture> NativeWidgetAura::CopyTexture() {
+ // The layer we create doesn't have an external texture, so this should never
+ // get invoked.
+ NOTREACHED();
+ return scoped_refptr<ui::Texture>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, ui::EventHandler implementation:
+
+void NativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) {
+ if (event->is_char()) {
+ // If a ui::InputMethod object is attached to the root window, character
+ // events are handled inside the object and are not passed to this function.
+ // If such object is not attached, character events might be sent (e.g. on
+ // Windows). In this case, we just skip these.
+ return;
+ }
+ // Renderer may send a key event back to us if the key event wasn't handled,
+ // and the window may be invisible by that time.
+ if (!window_->IsVisible())
+ return;
+ GetWidget()->GetInputMethod()->DispatchKeyEvent(*event);
+ event->SetHandled();
+}
+
+void NativeWidgetAura::OnMouseEvent(ui::MouseEvent* event) {
+ DCHECK(window_->IsVisible());
+ if (event->type() == ui::ET_MOUSEWHEEL) {
+ delegate_->OnMouseEvent(event);
+ if (event->handled())
+ return;
+ }
+
+ if (tooltip_manager_.get())
+ tooltip_manager_->UpdateTooltip();
+ delegate_->OnMouseEvent(event);
+}
+
+void NativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) {
+ delegate_->OnScrollEvent(event);
+}
+
+void NativeWidgetAura::OnTouchEvent(ui::TouchEvent* event) {
+ DCHECK(window_->IsVisible());
+ delegate_->OnTouchEvent(event);
+}
+
+void NativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
+ DCHECK(window_->IsVisible());
+ delegate_->OnGestureEvent(event);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, aura::client::ActivationDelegate implementation:
+
+bool NativeWidgetAura::ShouldActivate() const {
+ return can_activate_ && delegate_->CanActivate();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, aura::client::ActivationChangeObserver implementation:
+
+void NativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ DCHECK(window_ == gained_active || window_ == lost_active);
+ if (GetWidget()->GetFocusManager()) {
+ if (window_ == gained_active)
+ GetWidget()->GetFocusManager()->RestoreFocusedView();
+ else if (window_ == lost_active)
+ GetWidget()->GetFocusManager()->StoreFocusedView(true);
+ }
+ delegate_->OnNativeWidgetActivationChanged(window_ == gained_active);
+ if (IsVisible() && GetWidget()->non_client_view())
+ GetWidget()->non_client_view()->SchedulePaint();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, aura::client::FocusChangeObserver:
+
+void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ if (window_ == gained_focus) {
+ // In aura, it is possible for child native widgets to take input and focus,
+ // this differs from the behavior on windows.
+ if (GetWidget()->GetInputMethod()) // Null in tests.
+ GetWidget()->GetInputMethod()->OnFocus();
+ delegate_->OnNativeFocus(lost_focus);
+ } else if (window_ == lost_focus) {
+ // GetInputMethod() recreates the input method if it's previously been
+ // destroyed. If we get called during destruction, the input method will be
+ // gone, and creating a new one and telling it that we lost the focus will
+ // trigger a DCHECK (the new input method doesn't think that we have the
+ // focus and doesn't expect a blur). OnBlur() shouldn't be called during
+ // destruction unless WIDGET_OWNS_NATIVE_WIDGET is set (which is just the
+ // case in tests).
+ if (!destroying_) {
+ if (GetWidget()->GetInputMethod())
+ GetWidget()->GetInputMethod()->OnBlur();
+ } else {
+ DCHECK_EQ(ownership_, Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
+ }
+
+ aura::client::FocusClient* client = aura::client::GetFocusClient(window_);
+ if (client) // NULL during destruction of aura::Window.
+ delegate_->OnNativeBlur(client->GetFocusedWindow());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, aura::WindowDragDropDelegate implementation:
+
+void NativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_.get() != NULL);
+ last_drop_operation_ = drop_helper_->OnDragOver(event.data(),
+ event.location(), event.source_operations());
+}
+
+int NativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_.get() != NULL);
+ last_drop_operation_ = drop_helper_->OnDragOver(event.data(),
+ event.location(), event.source_operations());
+ return last_drop_operation_;
+}
+
+void NativeWidgetAura::OnDragExited() {
+ DCHECK(drop_helper_.get() != NULL);
+ drop_helper_->OnDragExit();
+}
+
+int NativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_.get() != NULL);
+ return drop_helper_->OnDrop(event.data(), event.location(),
+ last_drop_operation_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, NativeWidget implementation:
+
+ui::EventHandler* NativeWidgetAura::GetEventHandler() {
+ return this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, protected:
+
+NativeWidgetAura::~NativeWidgetAura() {
+ destroying_ = true;
+ if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ delete delegate_;
+ else
+ CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetAura, private:
+
+void NativeWidgetAura::SetInitialFocus() {
+ // The window does not get keyboard messages unless we focus it.
+ if (!GetWidget()->SetInitialFocus())
+ window_->Focus();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, public:
+
+// static
+void Widget::NotifyLocaleChanged() {
+ // Deliberately not implemented.
+}
+
+namespace {
+void CloseWindow(aura::Window* window) {
+ if (window) {
+ Widget* widget = Widget::GetWidgetForNativeView(window);
+ if (widget && widget->is_secondary_widget())
+ // To avoid the delay in shutdown caused by using Close which may wait
+ // for animations, use CloseNow. Because this is only used on secondary
+ // widgets it seems relatively safe to skip the extra processing of
+ // Close.
+ widget->CloseNow();
+ }
+}
+#if defined(OS_WIN)
+BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
+ aura::Window* root_window =
+ DesktopRootWindowHostWin::GetContentWindowForHWND(hwnd);
+ CloseWindow(root_window);
+ return TRUE;
+}
+#endif
+} // namespace
+
+// static
+void Widget::CloseAllSecondaryWidgets() {
+#if defined(OS_WIN)
+ EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0);
+#endif
+
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+ std::vector<aura::Window*> open_windows =
+ DesktopRootWindowHostX11::GetAllOpenWindows();
+ std::for_each(open_windows.begin(), open_windows.end(), CloseWindow);
+ DesktopRootWindowHostX11::CleanUpWindowList();
+#endif
+}
+
+bool Widget::ConvertRect(const Widget* source,
+ const Widget* target,
+ gfx::Rect* rect) {
+ return false;
+}
+
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// internal::NativeWidgetPrivate, public:
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
+ internal::NativeWidgetDelegate* delegate) {
+ return new NativeWidgetAura(delegate);
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
+ gfx::NativeView native_view) {
+ return reinterpret_cast<NativeWidgetPrivate*>(native_view->user_data());
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
+ gfx::NativeWindow native_window) {
+ return reinterpret_cast<NativeWidgetPrivate*>(native_window->user_data());
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
+ gfx::NativeView native_view) {
+ aura::Window* window = native_view;
+ NativeWidgetPrivate* top_level_native_widget = NULL;
+ while (window) {
+ NativeWidgetPrivate* native_widget = GetNativeWidgetForNativeView(window);
+ if (native_widget)
+ top_level_native_widget = native_widget;
+ window = window->parent();
+ }
+ return top_level_native_widget;
+}
+
+// static
+void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
+ Widget::Widgets* children) {
+ {
+ // Code expects widget for |native_view| to be added to |children|.
+ NativeWidgetPrivate* native_widget = static_cast<NativeWidgetPrivate*>(
+ GetNativeWidgetForNativeView(native_view));
+ if (native_widget && native_widget->GetWidget())
+ children->insert(native_widget->GetWidget());
+ }
+
+ const aura::Window::Windows& child_windows = native_view->children();
+ for (aura::Window::Windows::const_iterator i = child_windows.begin();
+ i != child_windows.end(); ++i) {
+ NativeWidgetAura* native_widget =
+ static_cast<NativeWidgetAura*>(GetNativeWidgetForNativeView(*i));
+ if (native_widget)
+ children->insert(native_widget->GetWidget());
+ }
+}
+
+// static
+void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
+ gfx::NativeView new_parent) {
+ DCHECK(native_view != new_parent);
+
+ gfx::NativeView previous_parent = native_view->parent();
+ if (previous_parent == new_parent)
+ return;
+
+ Widget::Widgets widgets;
+ GetAllChildWidgets(native_view, &widgets);
+
+ // First notify all the widgets that they are being disassociated
+ // from their previous parent.
+ for (Widget::Widgets::iterator it = widgets.begin();
+ it != widgets.end(); ++it) {
+ (*it)->NotifyNativeViewHierarchyChanged(false, previous_parent);
+ }
+
+ if (new_parent) {
+ new_parent->AddChild(native_view);
+ } else {
+ // The following looks weird, but it's the equivalent of what aura has
+ // always done. (The previous behaviour of aura::Window::SetParent() used
+ // NULL as a special value that meant ask the StackingClient where things
+ // should go.)
+ //
+ // This probably isn't strictly correct, but its an invariant that a Window
+ // in use will be attached to a RootWindow, so we can't just call
+ // RemoveChild here. The only possible thing that could assign a RootWindow
+ // in this case is the stacking client of the current RootWindow. This
+ // matches our previous behaviour; the global stacking client would almost
+ // always reattach the window to the same RootWindow.
+ aura::RootWindow* root_window = native_view->GetRootWindow();
+ native_view->SetDefaultParentByRootWindow(
+ root_window, root_window->GetBoundsInScreen());
+ }
+
+ // And now, notify them that they have a brand new parent.
+ for (Widget::Widgets::iterator it = widgets.begin();
+ it != widgets.end(); ++it) {
+ (*it)->NotifyNativeViewHierarchyChanged(true, new_parent);
+ }
+}
+
+// static
+bool NativeWidgetPrivate::IsMouseButtonDown() {
+ return aura::Env::GetInstance()->is_mouse_button_down();
+}
+
+// static
+bool NativeWidgetPrivate::IsTouchDown() {
+ return aura::Env::GetInstance()->is_touch_down();
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
new file mode 100644
index 00000000000..57271e81a98
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -0,0 +1,228 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_
+
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/aura/client/activation_change_observer.h"
+#include "ui/aura/client/activation_delegate.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/views/ime/input_method_delegate.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/native_widget_private.h"
+
+namespace aura {
+class Window;
+}
+namespace gfx {
+class Font;
+}
+
+namespace views {
+
+class DropHelper;
+class NativeWidgetAuraWindowObserver;
+class TooltipManagerAura;
+class WindowReorderer;
+
+class VIEWS_EXPORT NativeWidgetAura
+ : public internal::NativeWidgetPrivate,
+ public internal::InputMethodDelegate,
+ public aura::WindowDelegate,
+ public aura::client::ActivationDelegate,
+ public aura::client::ActivationChangeObserver,
+ public aura::client::FocusChangeObserver,
+ public aura::client::DragDropDelegate {
+ public:
+ explicit NativeWidgetAura(internal::NativeWidgetDelegate* delegate);
+
+ // TODO(beng): Find a better place for this, and the similar method on
+ // NativeWidgetWin.
+ static gfx::Font GetWindowTitleFont();
+
+ // Overridden from internal::NativeWidgetPrivate:
+ virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
+ virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
+ virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual const Widget* GetWidget() const OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
+ virtual Widget* GetTopLevelWidget() OVERRIDE;
+ virtual const ui::Compositor* GetCompositor() const OVERRIDE;
+ virtual ui::Compositor* GetCompositor() OVERRIDE;
+ virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
+ virtual void ViewRemoved(View* view) OVERRIDE;
+ virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
+ virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
+ virtual TooltipManager* GetTooltipManager() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual InputMethod* CreateInputMethod() OVERRIDE;
+ virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* maximized) const OVERRIDE;
+ virtual void SetWindowTitle(const string16& title) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void StackAbove(gfx::NativeView native_view) OVERRIDE;
+ virtual void StackAtTop() OVERRIDE;
+ virtual void StackBelow(gfx::NativeView native_view) OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion shape) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual void ShowWithWindowState(ui::WindowShowState state) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetUseDragFrame(bool use_drag_frame) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual bool IsMouseEventsEnabled() const OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetInactiveRenderingDisabled(bool value) OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
+
+ // Overridden from views::InputMethodDelegate:
+ virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE;
+
+ // Overridden from aura::WindowDelegate:
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE;
+ virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
+ virtual bool ShouldDescendIntoChildForEventHandling(
+ aura::Window* child,
+ const gfx::Point& location) OVERRIDE;
+ virtual bool CanFocus() OVERRIDE;
+ virtual void OnCaptureLost() OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void OnWindowDestroying() OVERRIDE;
+ virtual void OnWindowDestroyed() OVERRIDE;
+ virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
+ virtual bool HasHitTestMask() const OVERRIDE;
+ virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
+ virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE;
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ // Overridden from aura::client::ActivationDelegate:
+ virtual bool ShouldActivate() const OVERRIDE;
+
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE;
+
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE;
+
+ // Overridden from aura::client::DragDropDelegate:
+ virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragExited() OVERRIDE;
+ virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
+
+ // Overridden from NativeWidget:
+ virtual ui::EventHandler* GetEventHandler() OVERRIDE;
+
+ protected:
+ virtual ~NativeWidgetAura();
+
+ internal::NativeWidgetDelegate* delegate() { return delegate_; }
+
+ private:
+ class ActiveWindowObserver;
+
+ void SetInitialFocus();
+
+ internal::NativeWidgetDelegate* delegate_;
+
+ aura::Window* window_;
+
+ // See class documentation for Widget in widget.h for a note about ownership.
+ Widget::InitParams::Ownership ownership_;
+
+ // The following factory is used for calls to close the NativeWidgetAura
+ // instance.
+ base::WeakPtrFactory<NativeWidgetAura> close_widget_factory_;
+
+ // Can we be made active?
+ bool can_activate_;
+
+ // Are we in the destructor?
+ bool destroying_;
+
+ gfx::NativeCursor cursor_;
+
+ // The saved window state for exiting full screen state.
+ ui::WindowShowState saved_window_state_;
+
+ scoped_ptr<TooltipManagerAura> tooltip_manager_;
+
+ // Reorders child windows of |window_| associated with a view based on the
+ // order of the associated views in the widget's view hierarchy.
+ scoped_ptr<WindowReorderer> window_reorderer_;
+
+ scoped_ptr<NativeWidgetAuraWindowObserver> active_window_observer_;
+
+ scoped_ptr<DropHelper> drop_helper_;
+ int last_drop_operation_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetAura);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
new file mode 100644
index 00000000000..612616bc2c0
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -0,0 +1,412 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/native_widget_aura.h"
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/env.h"
+#include "ui/aura/layout_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/aura_test_helper.h"
+#include "ui/aura/window.h"
+#include "ui/base/events/event.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+namespace {
+
+NativeWidgetAura* Init(aura::Window* parent, Widget* widget) {
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = parent;
+ widget->Init(params);
+ return static_cast<NativeWidgetAura*>(widget->native_widget());
+}
+
+class NativeWidgetAuraTest : public testing::Test {
+ public:
+ NativeWidgetAuraTest() {}
+ virtual ~NativeWidgetAuraTest() {}
+
+ // testing::Test overrides:
+ virtual void SetUp() OVERRIDE {
+ aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
+ aura_test_helper_->SetUp();
+ root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
+ root_window()->SetHostSize(gfx::Size(640, 480));
+ }
+ virtual void TearDown() OVERRIDE {
+ message_loop_.RunUntilIdle();
+ aura_test_helper_->TearDown();
+ }
+
+ protected:
+ aura::RootWindow* root_window() { return aura_test_helper_->root_window(); }
+
+ private:
+ base::MessageLoopForUI message_loop_;
+ scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest);
+};
+
+TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) {
+ // Make a parent window larger than the host represented by rootwindow.
+ scoped_ptr<aura::Window> parent(new aura::Window(NULL));
+ parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->SetBounds(gfx::Rect(0, 0, 1024, 800));
+ scoped_ptr<Widget> widget(new Widget());
+ NativeWidgetAura* window = Init(parent.get(), widget.get());
+
+ window->CenterWindow(gfx::Size(100, 100));
+ EXPECT_EQ(gfx::Rect( (640 - 100) / 2,
+ (480 - 100) / 2,
+ 100, 100),
+ window->GetNativeWindow()->bounds());
+ widget->CloseNow();
+}
+
+TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) {
+ // Make a parent window smaller than the host represented by rootwindow.
+ scoped_ptr<aura::Window> parent(new aura::Window(NULL));
+ parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->SetBounds(gfx::Rect(0, 0, 480, 320));
+ scoped_ptr<Widget> widget(new Widget());
+ NativeWidgetAura* window = Init(parent.get(), widget.get());
+
+ window->CenterWindow(gfx::Size(100, 100));
+ EXPECT_EQ(gfx::Rect( (480 - 100) / 2,
+ (320 - 100) / 2,
+ 100, 100),
+ window->GetNativeWindow()->bounds());
+ widget->CloseNow();
+}
+
+// Verifies CenterWindow() constrains to parent size.
+TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) {
+ // Make a parent window smaller than the host represented by rootwindow and
+ // offset it slightly from the origin.
+ scoped_ptr<aura::Window> parent(new aura::Window(NULL));
+ parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->SetBounds(gfx::Rect(20, 40, 480, 320));
+ scoped_ptr<Widget> widget(new Widget());
+ NativeWidgetAura* window = Init(parent.get(), widget.get());
+ window->CenterWindow(gfx::Size(500, 600));
+
+ // |window| should be no bigger than |parent|.
+ EXPECT_EQ("20,40 480x320", window->GetNativeWindow()->bounds().ToString());
+ widget->CloseNow();
+}
+
+// Used by ShowMaximizedDoesntBounceAround. See it for details.
+class TestLayoutManager : public aura::LayoutManager {
+ public:
+ TestLayoutManager() {}
+
+ virtual void OnWindowResized() OVERRIDE {
+ }
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
+ // This simulates what happens when adding a maximized window.
+ SetChildBoundsDirect(child, gfx::Rect(0, 0, 300, 300));
+ }
+ virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
+ }
+ virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
+ }
+ virtual void OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) OVERRIDE {
+ }
+ virtual void SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) OVERRIDE {
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestLayoutManager);
+};
+
+// This simulates BrowserView, which creates a custom RootView so that
+// OnNativeWidgetSizeChanged that is invoked during Init matters.
+class TestWidget : public views::Widget {
+ public:
+ TestWidget() : did_size_change_more_than_once_(false) {
+ }
+
+ // Returns true if the size changes to a non-empty size, and then to another
+ // size.
+ bool did_size_change_more_than_once() const {
+ return did_size_change_more_than_once_;
+ }
+
+ virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) OVERRIDE {
+ if (last_size_.IsEmpty())
+ last_size_ = new_size;
+ else if (!did_size_change_more_than_once_ && new_size != last_size_)
+ did_size_change_more_than_once_ = true;
+ Widget::OnNativeWidgetSizeChanged(new_size);
+ }
+
+ private:
+ bool did_size_change_more_than_once_;
+ gfx::Size last_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWidget);
+};
+
+// Verifies the size of the widget doesn't change more than once during Init if
+// the window ends up maximized. This is important as otherwise
+// RenderWidgetHostViewAura ends up getting resized during construction, which
+// leads to noticable flashes.
+TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) {
+ root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
+ root_window()->SetLayoutManager(new TestLayoutManager);
+ scoped_ptr<TestWidget> widget(new TestWidget());
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = NULL;
+ params.context = root_window();
+ params.show_state = ui::SHOW_STATE_MAXIMIZED;
+ params.bounds = gfx::Rect(10, 10, 100, 200);
+ widget->Init(params);
+ EXPECT_FALSE(widget->did_size_change_more_than_once());
+ widget->CloseNow();
+}
+
+TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) {
+ // Create a widget.
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.context = root_window();
+ params.bounds.SetRect(10, 20, 300, 400);
+ scoped_ptr<Widget> widget(new Widget());
+ widget->Init(params);
+
+ // For Aura, client area bounds match window bounds.
+ gfx::Rect client_bounds = widget->GetClientAreaBoundsInScreen();
+ EXPECT_EQ(10, client_bounds.x());
+ EXPECT_EQ(20, client_bounds.y());
+ EXPECT_EQ(300, client_bounds.width());
+ EXPECT_EQ(400, client_bounds.height());
+}
+
+namespace {
+
+// View subclass that tracks whether it has gotten a gesture event.
+class GestureTrackingView : public views::View {
+ public:
+ GestureTrackingView()
+ : got_gesture_event_(false),
+ consume_gesture_event_(true) {}
+
+ void set_consume_gesture_event(bool value) {
+ consume_gesture_event_ = value;
+ }
+
+ void clear_got_gesture_event() {
+ got_gesture_event_ = false;
+ }
+ bool got_gesture_event() const {
+ return got_gesture_event_;
+ }
+
+ // View overrides:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ got_gesture_event_ = true;
+ if (consume_gesture_event_)
+ event->StopPropagation();
+ }
+
+ private:
+ // Was OnGestureEvent() invoked?
+ bool got_gesture_event_;
+
+ // Dictates what OnGestureEvent() returns.
+ bool consume_gesture_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureTrackingView);
+};
+
+} // namespace
+
+// Verifies a capture isn't set on touch press and that the view that gets
+// the press gets the release.
+TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
+ // Create two views (both sized the same). |child| is configured not to
+ // consume the gesture event.
+ GestureTrackingView* view = new GestureTrackingView();
+ GestureTrackingView* child = new GestureTrackingView();
+ child->set_consume_gesture_event(false);
+ view->SetLayoutManager(new FillLayout);
+ view->AddChildView(child);
+ scoped_ptr<TestWidget> widget(new TestWidget());
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.context = root_window();
+ params.bounds = gfx::Rect(0, 0, 100, 200);
+ widget->Init(params);
+ widget->SetContentsView(view);
+ widget->Show();
+
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1,
+ base::TimeDelta());
+ root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ // Both views should get the press.
+ EXPECT_TRUE(view->got_gesture_event());
+ EXPECT_TRUE(child->got_gesture_event());
+ view->clear_got_gesture_event();
+ child->clear_got_gesture_event();
+ // Touch events should not automatically grab capture.
+ EXPECT_FALSE(widget->HasCapture());
+
+ // Release touch. Only |view| should get the release since that it consumed
+ // the press.
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), 1,
+ base::TimeDelta());
+ root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ EXPECT_TRUE(view->got_gesture_event());
+ EXPECT_FALSE(child->got_gesture_event());
+ view->clear_got_gesture_event();
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ widget->Close();
+}
+
+TEST_F(NativeWidgetAuraTest, ReleaseCaptureOnTouchRelease) {
+ GestureTrackingView* view = new GestureTrackingView();
+ scoped_ptr<TestWidget> widget(new TestWidget());
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.context = root_window();
+ params.bounds = gfx::Rect(0, 0, 100, 200);
+ widget->Init(params);
+ widget->SetContentsView(view);
+ widget->Show();
+
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1,
+ base::TimeDelta());
+ root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ EXPECT_TRUE(view->got_gesture_event());
+ view->clear_got_gesture_event();
+ // Set the capture.
+ widget->SetCapture(view);
+ EXPECT_TRUE(widget->HasCapture());
+
+ // Generate a release, this should trigger releasing capture.
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(41, 51), 1,
+ base::TimeDelta());
+ root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ EXPECT_TRUE(view->got_gesture_event());
+ view->clear_got_gesture_event();
+ EXPECT_FALSE(widget->HasCapture());
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ widget->Close();
+}
+
+// Verifies views with layers are targeted for events properly.
+TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
+ // Create two widgets: |parent| and |child|. |child| is a child of |parent|.
+ views::View* parent_root = new views::View;
+ scoped_ptr<Widget> parent(new Widget());
+ Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ parent_params.ownership =
+ views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ parent_params.context = root_window();
+ parent->Init(parent_params);
+ parent->SetContentsView(parent_root);
+ parent->SetBounds(gfx::Rect(0, 0, 400, 400));
+ parent->Show();
+
+ scoped_ptr<Widget> child(new Widget());
+ Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
+ child_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ child_params.parent = parent->GetNativeWindow();
+ child->Init(child_params);
+ child->SetBounds(gfx::Rect(0, 0, 200, 200));
+ child->Show();
+
+ // Point is over |child|.
+ EXPECT_EQ(child->GetNativeWindow(),
+ parent->GetNativeWindow()->GetEventHandlerForPoint(
+ gfx::Point(50, 50)));
+
+ // Create a view with a layer and stack it at the bottom (below |child|).
+ views::View* view_with_layer = new views::View;
+ parent_root->AddChildView(view_with_layer);
+ view_with_layer->SetBounds(0, 0, 50, 50);
+ view_with_layer->SetPaintToLayer(true);
+
+ // Make sure that |child| still gets the event.
+ EXPECT_EQ(child->GetNativeWindow(),
+ parent->GetNativeWindow()->GetEventHandlerForPoint(
+ gfx::Point(20, 20)));
+
+ // Move |view_with_layer| to the top and make sure it gets the
+ // event when the point is within |view_with_layer|'s bounds.
+ view_with_layer->layer()->parent()->StackAtTop(
+ view_with_layer->layer());
+ EXPECT_EQ(parent->GetNativeWindow(),
+ parent->GetNativeWindow()->GetEventHandlerForPoint(
+ gfx::Point(20, 20)));
+
+ // Point is over |child|, it should get the event.
+ EXPECT_EQ(child->GetNativeWindow(),
+ parent->GetNativeWindow()->GetEventHandlerForPoint(
+ gfx::Point(70, 70)));
+
+ delete view_with_layer;
+ view_with_layer = NULL;
+
+ EXPECT_EQ(child->GetNativeWindow(),
+ parent->GetNativeWindow()->GetEventHandlerForPoint(
+ gfx::Point(20, 20)));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+// Verifies that widget->FlashFrame() sets aura::client::kDrawAttentionKey,
+// and activating the window clears it.
+TEST_F(NativeWidgetAuraTest, FlashFrame) {
+ scoped_ptr<Widget> widget(new Widget());
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.context = root_window();
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+ aura::Window* window = widget->GetNativeWindow();
+ EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
+ widget->FlashFrame(true);
+ EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
+ widget->FlashFrame(false);
+ EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
+ widget->FlashFrame(true);
+ EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
+ widget->Activate();
+ EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
+}
+
+TEST_F(NativeWidgetAuraTest, NoCrashOnThemeAfterClose) {
+ scoped_ptr<aura::Window> parent(new aura::Window(NULL));
+ parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->SetBounds(gfx::Rect(0, 0, 480, 320));
+ scoped_ptr<Widget> widget(new Widget());
+ NativeWidgetAura* window = Init(parent.get(), widget.get());
+ window->Show();
+ window->Close();
+ base::MessageLoop::current()->RunUntilIdle();
+ widget->GetNativeTheme(); // Shouldn't crash.
+}
+
+} // namespace
+} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_aura_window_observer.cc b/chromium/ui/views/widget/native_widget_aura_window_observer.cc
new file mode 100644
index 00000000000..3be33dd818c
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_aura_window_observer.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/native_widget_aura_window_observer.h"
+
+#include "ui/aura/client/activation_client.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+
+namespace views {
+
+NativeWidgetAuraWindowObserver::NativeWidgetAuraWindowObserver(
+ gfx::NativeView native_view,
+ internal::NativeWidgetDelegate* delegate)
+ : native_view_(native_view),
+ delegate_(delegate) {
+ native_view_->GetRootWindow()->AddObserver(this);
+ native_view_->AddObserver(this);
+ aura::client::GetActivationClient(native_view_->GetRootWindow())->
+ AddObserver(this);
+}
+
+NativeWidgetAuraWindowObserver::~NativeWidgetAuraWindowObserver() {
+ CleanUpObservers();
+}
+
+void NativeWidgetAuraWindowObserver::OnWindowActivated(
+ aura::Window* gained_active,
+ aura::Window* lost_active) {
+ if (!gained_active || gained_active->transient_parent() != native_view_)
+ delegate_->EnableInactiveRendering();
+}
+
+void NativeWidgetAuraWindowObserver::OnWindowRemovingFromRootWindow(
+ aura::Window* window) {
+ if (window != native_view_)
+ return;
+ CleanUpObservers();
+}
+
+void NativeWidgetAuraWindowObserver::CleanUpObservers() {
+ if (!native_view_)
+ return;
+ native_view_->GetRootWindow()->RemoveObserver(this);
+ native_view_->RemoveObserver(this);
+ aura::client::GetActivationClient(native_view_->GetRootWindow())->
+ RemoveObserver(this);
+ native_view_ = NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_aura_window_observer.h b/chromium/ui/views/widget/native_widget_aura_window_observer.h
new file mode 100644
index 00000000000..70a6037b3a9
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_aura_window_observer.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_WINDOW_OBSERVER_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_WINDOW_OBSERVER_H_
+
+#include "base/compiler_specific.h"
+#include "ui/aura/client/activation_change_observer.h"
+#include "ui/aura/window_observer.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/widget/native_widget_private.h"
+
+namespace views {
+
+// A helper class shared between NativeWidgetAura implementations. Used when
+// SetInactiveRenderingDisabled() is invoked to track when active status
+// changes in such a way that we should enable inactive rendering.
+class NativeWidgetAuraWindowObserver
+ : public aura::WindowObserver,
+ public aura::client::ActivationChangeObserver {
+ public:
+ explicit NativeWidgetAuraWindowObserver(
+ gfx::NativeView native_view,
+ internal::NativeWidgetDelegate* delegate);
+ virtual ~NativeWidgetAuraWindowObserver();
+
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE;
+
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE;
+
+ private:
+ void CleanUpObservers();
+
+ gfx::NativeView native_view_;
+ internal::NativeWidgetDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraWindowObserver);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_WINDOW_OBSERVER_H_
diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h
new file mode 100644
index 00000000000..c1fd073370e
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_delegate.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_DELEGATE_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_DELEGATE_H_
+
+#include <vector>
+
+#include "ui/base/events/event_constants.h"
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Canvas;
+class Path;
+class Point;
+class Size;
+}
+
+namespace ui {
+class GestureEvent;
+class KeyEvent;
+class Layer;
+class MouseEvent;
+class TouchEvent;
+class ScrollEvent;
+}
+
+namespace views {
+class InputMethod;
+class Widget;
+
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetDelegate
+//
+// An interface implemented by the object that handles events sent by a
+// NativeWidget implementation.
+//
+class VIEWS_EXPORT NativeWidgetDelegate {
+ public:
+ virtual ~NativeWidgetDelegate() {}
+
+ // Returns true if the window is modal.
+ virtual bool IsModal() const = 0;
+
+ // Returns true if the window is a dialog box.
+ virtual bool IsDialogBox() const = 0;
+
+ // Returns true if the window can be activated.
+ virtual bool CanActivate() const = 0;
+
+ virtual bool IsInactiveRenderingDisabled() const = 0;
+ virtual void EnableInactiveRendering() = 0;
+
+ // Called when the activation state of a window has changed.
+ virtual void OnNativeWidgetActivationChanged(bool active) = 0;
+
+ // Called when native focus moves from one native view to another.
+ virtual void OnNativeFocus(gfx::NativeView focused_view) = 0;
+ virtual void OnNativeBlur(gfx::NativeView focused_view) = 0;
+
+ // Called when the window is shown/hidden.
+ virtual void OnNativeWidgetVisibilityChanged(bool visible) = 0;
+
+ // Called when the native widget is created.
+ // The |desktop_widget| bool is true for widgets created in the desktop and
+ // false for widgets created in the shell.
+ virtual void OnNativeWidgetCreated(bool desktop_widget) = 0;
+
+ // Called just before the native widget is destroyed. This is the delegate's
+ // last chance to do anything with the native widget handle.
+ virtual void OnNativeWidgetDestroying() = 0;
+
+ // Called just after the native widget is destroyed.
+ virtual void OnNativeWidgetDestroyed() = 0;
+
+ // Returns the smallest size the window can be resized to by the user.
+ virtual gfx::Size GetMinimumSize() = 0;
+
+ // Returns the largest size the window can be resized to by the user.
+ virtual gfx::Size GetMaximumSize() = 0;
+
+ // Called when the NativeWidget changed position.
+ virtual void OnNativeWidgetMove() = 0;
+
+ // Called when the NativeWidget changed size to |new_size|.
+ virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) = 0;
+
+ // Called when the user begins/ends to change the bounds of the window.
+ virtual void OnNativeWidgetBeginUserBoundsChange() = 0;
+ virtual void OnNativeWidgetEndUserBoundsChange() = 0;
+
+ // Returns true if the delegate has a FocusManager.
+ virtual bool HasFocusManager() const = 0;
+
+ // Paints the widget using acceleration. If the widget is not using
+ // accelerated painting this returns false and does nothing.
+ virtual bool OnNativeWidgetPaintAccelerated(
+ const gfx::Rect& dirty_region) = 0;
+
+ // Paints the rootview in the canvas. This will also refresh the compositor
+ // tree if necessary when accelerated painting is enabled.
+ virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) = 0;
+
+ // Returns the non-client component (see ui/base/hit_test.h) containing
+ // |point|, in client coordinates.
+ virtual int GetNonClientComponent(const gfx::Point& point) = 0;
+
+ // Mouse and key event handlers.
+ virtual void OnKeyEvent(ui::KeyEvent* event) = 0;
+ virtual void OnMouseEvent(ui::MouseEvent* event) = 0;
+ virtual void OnMouseCaptureLost() = 0;
+
+ virtual void OnTouchEvent(ui::TouchEvent* event) = 0;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) = 0;
+ virtual void OnGestureEvent(ui::GestureEvent* event) = 0;
+
+ // Runs the specified native command. Returns true if the command is handled.
+ virtual bool ExecuteCommand(int command_id) = 0;
+
+ // Returns the input method of the widget this delegate is associated with.
+ // Note that this does not use the top level widget, so may return NULL
+ // if the widget doesn't have input method.
+ virtual InputMethod* GetInputMethodDirect() = 0;
+
+ // Returns the child Layers of the Widgets layer that were created by Views.
+ virtual const std::vector<ui::Layer*>& GetRootLayers() = 0;
+
+ // Returns true if window has a hit-test mask.
+ virtual bool HasHitTestMask() const = 0;
+
+ // Provides the hit-test mask if HasHitTestMask above returns true.
+ virtual void GetHitTestMask(gfx::Path* mask) const = 0;
+
+ //
+ virtual Widget* AsWidget() = 0;
+ virtual const Widget* AsWidget() const = 0;
+};
+
+} // namespace internal
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_DELEGATE_H_
diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h
new file mode 100644
index 00000000000..3bdd6810cfc
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_private.h
@@ -0,0 +1,225 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_
+
+#include "base/strings/string16.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/ime/input_method_delegate.h"
+#include "ui/views/widget/native_widget.h"
+
+namespace gfx {
+class ImageSkia;
+class Rect;
+}
+
+namespace ui {
+class NativeTheme;
+class OSExchangeData;
+}
+
+namespace views {
+class InputMethod;
+class TooltipManager;
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetPrivate interface
+//
+// A NativeWidget subclass internal to views that provides Widget a conduit for
+// communication with a backend-specific native widget implementation.
+//
+// Many of the methods here are pass-thrus for Widget, and as such there is no
+// documentation for them here. In that case, see methods of the same name in
+// widget.h.
+//
+// IMPORTANT: This type is intended for use only by the views system and for
+// NativeWidget implementations. This file should not be included
+// in code that does not fall into one of these use cases.
+//
+class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
+ public:
+ virtual ~NativeWidgetPrivate() {}
+
+ // Creates an appropriate default NativeWidgetPrivate implementation for the
+ // current OS/circumstance.
+ static NativeWidgetPrivate* CreateNativeWidget(
+ internal::NativeWidgetDelegate* delegate);
+
+ static NativeWidgetPrivate* GetNativeWidgetForNativeView(
+ gfx::NativeView native_view);
+ static NativeWidgetPrivate* GetNativeWidgetForNativeWindow(
+ gfx::NativeWindow native_window);
+
+ // Retrieves the top NativeWidgetPrivate in the hierarchy containing the given
+ // NativeView, or NULL if there is no NativeWidgetPrivate that contains it.
+ static NativeWidgetPrivate* GetTopLevelNativeWidget(
+ gfx::NativeView native_view);
+
+ static void GetAllChildWidgets(gfx::NativeView native_view,
+ Widget::Widgets* children);
+ static void ReparentNativeView(gfx::NativeView native_view,
+ gfx::NativeView new_parent);
+
+ // Returns true if any mouse button is currently down.
+ static bool IsMouseButtonDown();
+
+ // Returns true if any touch device is currently down.
+ static bool IsTouchDown();
+
+ // Initializes the NativeWidget.
+ virtual void InitNativeWidget(const Widget::InitParams& params) = 0;
+
+ // Returns a NonClientFrameView for the widget's NonClientView, or NULL if
+ // the NativeWidget wants no special NonClientFrameView.
+ virtual NonClientFrameView* CreateNonClientFrameView() = 0;
+
+ virtual bool ShouldUseNativeFrame() const = 0;
+ virtual void FrameTypeChanged() = 0;
+
+ // Returns the Widget associated with this NativeWidget. This function is
+ // guaranteed to return non-NULL for the lifetime of the NativeWidget.
+ virtual Widget* GetWidget() = 0;
+ virtual const Widget* GetWidget() const = 0;
+
+ // Returns the NativeView/Window associated with this NativeWidget.
+ virtual gfx::NativeView GetNativeView() const = 0;
+ virtual gfx::NativeWindow GetNativeWindow() const = 0;
+
+ // Returns the topmost Widget in a hierarchy.
+ virtual Widget* GetTopLevelWidget() = 0;
+
+ // Returns the Compositor, or NULL if there isn't one associated with this
+ // NativeWidget.
+ virtual const ui::Compositor* GetCompositor() const = 0;
+ virtual ui::Compositor* GetCompositor() = 0;
+
+ // Returns the NativeWidget's layer, if any.
+ virtual ui::Layer* GetLayer() = 0;
+
+ // Reorders the widget's child NativeViews which are associated to the view
+ // tree (eg via a NativeViewHost) to match the z-order of the views in the
+ // view tree. The z-order of views with layers relative to views with
+ // associated NativeViews is used to reorder the NativeView layers. This
+ // method assumes that the widget's child layers which are owned by a view are
+ // already in the correct z-order relative to each other and does no
+ // reordering if there are no views with an associated NativeView.
+ virtual void ReorderNativeViews() = 0;
+
+ // Notifies the NativeWidget that a view was removed from the Widget's view
+ // hierarchy.
+ virtual void ViewRemoved(View* view) = 0;
+
+ // Sets/Gets a native window property on the underlying native window object.
+ // Returns NULL if the property does not exist. Setting the property value to
+ // NULL removes the property.
+ virtual void SetNativeWindowProperty(const char* name, void* value) = 0;
+ virtual void* GetNativeWindowProperty(const char* name) const = 0;
+
+ // Returns the native widget's tooltip manager. Called from the View hierarchy
+ // to update tooltips.
+ virtual TooltipManager* GetTooltipManager() const = 0;
+
+ // Sets or releases event capturing for this native widget.
+ virtual void SetCapture() = 0;
+ virtual void ReleaseCapture() = 0;
+
+ // Returns true if this native widget is capturing events.
+ virtual bool HasCapture() const = 0;
+
+ // Returns the InputMethod for this native widget.
+ // Note that all widgets in a widget hierarchy share the same input method.
+ // TODO(suzhe): rename to GetInputMethod() when NativeWidget implementation
+ // class doesn't inherit Widget anymore.
+ virtual InputMethod* CreateInputMethod() = 0;
+
+ // Returns the InputMethodDelegate for this native widget.
+ virtual InputMethodDelegate* GetInputMethodDelegate() = 0;
+
+
+ // Centers the window and sizes it to the specified size.
+ virtual void CenterWindow(const gfx::Size& size) = 0;
+
+ // Retrieves the window's current restored bounds and "show" state, for
+ // persisting.
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const = 0;
+
+ // Sets the NativeWindow title.
+ virtual void SetWindowTitle(const string16& title) = 0;
+
+ // Sets the Window icons. |window_icon| is a 16x16 icon suitable for use in
+ // a title bar. |app_icon| is a larger size for use in the host environment
+ // app switching UI.
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) = 0;
+
+ // Initializes the modal type of the window to |modal_type|. Called from
+ // NativeWidgetDelegate::OnNativeWidgetCreated() before the widget is
+ // initially parented.
+ virtual void InitModalType(ui::ModalType modal_type) = 0;
+
+ // See method documentation in Widget.
+ virtual gfx::Rect GetWindowBoundsInScreen() const = 0;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const = 0;
+ virtual gfx::Rect GetRestoredBounds() const = 0;
+ virtual void SetBounds(const gfx::Rect& bounds) = 0;
+ virtual void SetSize(const gfx::Size& size) = 0;
+ virtual void StackAbove(gfx::NativeView native_view) = 0;
+ virtual void StackAtTop() = 0;
+ virtual void StackBelow(gfx::NativeView native_view) = 0;
+ virtual void SetShape(gfx::NativeRegion shape) = 0;
+ virtual void Close() = 0;
+ virtual void CloseNow() = 0;
+ virtual void Show() = 0;
+ virtual void Hide() = 0;
+ // Invoked if the initial show should maximize the window. |restored_bounds|
+ // is the bounds of the window when not maximized.
+ virtual void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) = 0;
+ virtual void ShowWithWindowState(ui::WindowShowState show_state) = 0;
+ virtual bool IsVisible() const = 0;
+ virtual void Activate() = 0;
+ virtual void Deactivate() = 0;
+ virtual bool IsActive() const = 0;
+ virtual void SetAlwaysOnTop(bool always_on_top) = 0;
+ virtual void Maximize() = 0;
+ virtual void Minimize() = 0;
+ virtual bool IsMaximized() const = 0;
+ virtual bool IsMinimized() const = 0;
+ virtual void Restore() = 0;
+ virtual void SetFullscreen(bool fullscreen) = 0;
+ virtual bool IsFullscreen() const = 0;
+ virtual void SetOpacity(unsigned char opacity) = 0;
+ virtual void SetUseDragFrame(bool use_drag_frame) = 0;
+ virtual void FlashFrame(bool flash) = 0;
+ virtual void RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) = 0;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
+ virtual void SetCursor(gfx::NativeCursor cursor) = 0;
+ virtual bool IsMouseEventsEnabled() const = 0;
+ virtual void ClearNativeFocus() = 0;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0;
+ virtual void SetInactiveRenderingDisabled(bool value) = 0;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) = 0;
+ virtual void EndMoveLoop() = 0;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) = 0;
+ virtual ui::NativeTheme* GetNativeTheme() const = 0;
+
+ // Overridden from NativeWidget:
+ virtual internal::NativeWidgetPrivate* AsNativeWidgetPrivate() OVERRIDE;
+ virtual ui::EventHandler* GetEventHandler() = 0;
+};
+
+} // namespace internal
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_
diff --git a/chromium/ui/views/widget/native_widget_unittest.cc b/chromium/ui/views/widget/native_widget_unittest.cc
new file mode 100644
index 00000000000..133f8be04a5
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/native_widget_private.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+class ScopedTestWidget {
+ public:
+ explicit ScopedTestWidget(internal::NativeWidgetPrivate* native_widget)
+ : native_widget_(native_widget) {
+ }
+ ~ScopedTestWidget() {
+ // |CloseNow| deletes both |native_widget_| and its associated
+ // |Widget|.
+ native_widget_->GetWidget()->CloseNow();
+ }
+
+ internal::NativeWidgetPrivate* operator->() const {
+ return native_widget_;
+ }
+ internal::NativeWidgetPrivate* get() const { return native_widget_; }
+
+ private:
+ internal::NativeWidgetPrivate* native_widget_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedTestWidget);
+};
+
+class NativeWidgetTest : public ViewsTestBase {
+ public:
+ NativeWidgetTest() {}
+ virtual ~NativeWidgetTest() {}
+
+ internal::NativeWidgetPrivate* CreateNativeWidgetOfType(
+ Widget::InitParams::Type type) {
+ Widget* widget = new Widget;
+ Widget::InitParams params = CreateParams(type);
+ params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
+ params.child = false; // Implicitly set to true by ctor with TYPE_CONTROL.
+ params.bounds = gfx::Rect(10, 10, 200, 200);
+ widget->Init(params);
+ return widget->native_widget_private();
+ }
+
+ internal::NativeWidgetPrivate* CreateNativeWidget() {
+ return CreateNativeWidgetOfType(Widget::InitParams::TYPE_POPUP);
+ }
+
+ internal::NativeWidgetPrivate* CreateNativeSubWidget() {
+ return CreateNativeWidgetOfType(Widget::InitParams::TYPE_CONTROL);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetTest);
+};
+
+TEST_F(NativeWidgetTest, CreateNativeWidget) {
+ ScopedTestWidget widget(CreateNativeWidget());
+ EXPECT_TRUE(widget->GetWidget()->GetNativeView() != NULL);
+}
+
+TEST_F(NativeWidgetTest, GetNativeWidgetForNativeView) {
+ ScopedTestWidget widget(CreateNativeWidget());
+ EXPECT_EQ(widget.get(),
+ internal::NativeWidgetPrivate::GetNativeWidgetForNativeView(
+ widget->GetWidget()->GetNativeView()));
+}
+
+// |widget| has the toplevel NativeWidget.
+TEST_F(NativeWidgetTest, GetTopLevelNativeWidget1) {
+ ScopedTestWidget widget(CreateNativeWidget());
+ EXPECT_EQ(widget.get(),
+ internal::NativeWidgetPrivate::GetTopLevelNativeWidget(
+ widget->GetWidget()->GetNativeView()));
+}
+
+// |toplevel_widget| has the toplevel NativeWidget.
+TEST_F(NativeWidgetTest, GetTopLevelNativeWidget2) {
+ ScopedTestWidget toplevel_widget(CreateNativeWidget());
+
+ // |toplevel_widget| owns |child_host|.
+ NativeViewHost* child_host = new NativeViewHost;
+ toplevel_widget->GetWidget()->SetContentsView(child_host);
+
+ // |child_host| owns |child_widget|.
+ internal::NativeWidgetPrivate* child_widget = CreateNativeSubWidget();
+ child_host->Attach(child_widget->GetWidget()->GetNativeView());
+
+ EXPECT_EQ(toplevel_widget.get(),
+ internal::NativeWidgetPrivate::GetTopLevelNativeWidget(
+ child_widget->GetWidget()->GetNativeView()));
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_win.cc b/chromium/ui/views/widget/native_widget_win.cc
new file mode 100644
index 00000000000..d6ebdd6d664
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_win.cc
@@ -0,0 +1,1040 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/native_widget_win.h"
+
+#include <dwmapi.h>
+#include <shellapi.h>
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/strings/string_util.h"
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/drag_source_win.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
+#include "ui/base/events/event.h"
+#include "ui/base/ime/input_method_factory.h"
+#include "ui/base/keycodes/keyboard_code_conversion_win.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/theme_provider.h"
+#include "ui/base/view_prop.h"
+#include "ui/base/win/dpi.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/base/win/mouse_wheel_util.h"
+#include "ui/base/win/shell.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/canvas_skia_paint.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/point_conversions.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/controls/native_control_win.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/drag_utils.h"
+#include "ui/views/focus/accelerator_handler.h"
+#include "ui/views/focus/view_storage.h"
+#include "ui/views/focus/widget_focus_manager.h"
+#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/widget/aero_tooltip_manager.h"
+#include "ui/views/widget/drop_target_win.h"
+#include "ui/views/widget/monitor_win.h"
+#include "ui/views/widget/native_widget_delegate.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_hwnd_utils.h"
+#include "ui/views/win/fullscreen_handler.h"
+#include "ui/views/win/hwnd_message_handler.h"
+#include "ui/views/window/native_frame_view.h"
+
+#pragma comment(lib, "dwmapi.lib")
+
+using ui::ViewProp;
+
+namespace views {
+
+namespace {
+
+// Enumeration callback for NativeWidget::GetAllChildWidgets(). Called for each
+// child HWND beneath the original HWND.
+BOOL CALLBACK EnumerateChildWindowsForNativeWidgets(HWND hwnd, LPARAM l_param) {
+ Widget* widget = Widget::GetWidgetForNativeView(hwnd);
+ if (widget) {
+ Widget::Widgets* widgets = reinterpret_cast<Widget::Widgets*>(l_param);
+ widgets->insert(widget);
+ }
+ return TRUE;
+}
+
+// Links the HWND to its NativeWidget.
+const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__";
+
+const int kDragFrameWindowAlpha = 200;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, public:
+
+NativeWidgetWin::NativeWidgetWin(internal::NativeWidgetDelegate* delegate)
+ : delegate_(delegate),
+ ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
+ drag_frame_saved_window_style_(0),
+ drag_frame_saved_window_ex_style_(0),
+ has_non_client_view_(false),
+ message_handler_(new HWNDMessageHandler(this)) {
+}
+
+NativeWidgetWin::~NativeWidgetWin() {
+ if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ delete delegate_;
+ else
+ CloseNow();
+ message_handler_.reset();
+}
+
+// static
+gfx::Font NativeWidgetWin::GetWindowTitleFont() {
+ NONCLIENTMETRICS ncm;
+ base::win::GetNonClientMetrics(&ncm);
+ l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
+ base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
+ return gfx::Font(caption_font);
+}
+
+void NativeWidgetWin::Show(int show_state) {
+ message_handler_->Show(show_state);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, NativeWidget implementation:
+
+void NativeWidgetWin::InitNativeWidget(const Widget::InitParams& params) {
+ gfx::Rect pixel_bounds = ui::win::DIPToScreenRect(params.bounds);
+ Widget::InitParams params_in_pixel(params);
+ params_in_pixel.bounds = pixel_bounds;
+ SetInitParams(params_in_pixel);
+ message_handler_->Init(params.parent, pixel_bounds);
+}
+
+NonClientFrameView* NativeWidgetWin::CreateNonClientFrameView() {
+ return GetWidget()->ShouldUseNativeFrame() ?
+ new NativeFrameView(GetWidget()) : NULL;
+}
+
+bool NativeWidgetWin::ShouldUseNativeFrame() const {
+ return ui::win::IsAeroGlassEnabled();
+}
+
+void NativeWidgetWin::FrameTypeChanged() {
+ message_handler_->FrameTypeChanged();
+}
+
+Widget* NativeWidgetWin::GetWidget() {
+ return delegate_->AsWidget();
+}
+
+const Widget* NativeWidgetWin::GetWidget() const {
+ return delegate_->AsWidget();
+}
+
+gfx::NativeView NativeWidgetWin::GetNativeView() const {
+ return message_handler_->hwnd();
+}
+
+gfx::NativeWindow NativeWidgetWin::GetNativeWindow() const {
+ return message_handler_->hwnd();
+}
+
+Widget* NativeWidgetWin::GetTopLevelWidget() {
+ NativeWidgetPrivate* native_widget = GetTopLevelNativeWidget(GetNativeView());
+ return native_widget ? native_widget->GetWidget() : NULL;
+}
+
+const ui::Compositor* NativeWidgetWin::GetCompositor() const {
+ return NULL;
+}
+
+ui::Compositor* NativeWidgetWin::GetCompositor() {
+ return NULL;
+}
+
+ui::Layer* NativeWidgetWin::GetLayer() {
+ return NULL;
+}
+
+void NativeWidgetWin::ReorderNativeViews() {
+}
+
+void NativeWidgetWin::ViewRemoved(View* view) {
+ if (drop_target_.get())
+ drop_target_->ResetTargetViewIfEquals(view);
+}
+
+void NativeWidgetWin::SetNativeWindowProperty(const char* name, void* value) {
+ // Remove the existing property (if any).
+ for (ViewProps::iterator i = props_.begin(); i != props_.end(); ++i) {
+ if ((*i)->Key() == name) {
+ props_.erase(i);
+ break;
+ }
+ }
+
+ if (value)
+ props_.push_back(new ViewProp(GetNativeView(), name, value));
+}
+
+void* NativeWidgetWin::GetNativeWindowProperty(const char* name) const {
+ return ViewProp::GetValue(GetNativeView(), name);
+}
+
+TooltipManager* NativeWidgetWin::GetTooltipManager() const {
+ return tooltip_manager_.get();
+}
+
+void NativeWidgetWin::SetCapture() {
+ message_handler_->SetCapture();
+}
+
+void NativeWidgetWin::ReleaseCapture() {
+ message_handler_->ReleaseCapture();
+}
+
+bool NativeWidgetWin::HasCapture() const {
+ return message_handler_->HasCapture();
+}
+
+InputMethod* NativeWidgetWin::CreateInputMethod() {
+ return new InputMethodBridge(GetMessageHandler(), ui::GetSharedInputMethod(),
+ true);
+}
+
+internal::InputMethodDelegate* NativeWidgetWin::GetInputMethodDelegate() {
+ return message_handler_.get();
+}
+
+void NativeWidgetWin::CenterWindow(const gfx::Size& size) {
+ gfx::Size size_in_pixels = ui::win::DIPToScreenSize(size);
+ message_handler_->CenterWindow(size_in_pixels);
+}
+
+void NativeWidgetWin::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ message_handler_->GetWindowPlacement(bounds, show_state);
+ *bounds = ui::win::ScreenToDIPRect(*bounds);
+}
+
+void NativeWidgetWin::SetWindowTitle(const string16& title) {
+ message_handler_->SetTitle(title);
+}
+
+void NativeWidgetWin::SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) {
+ message_handler_->SetWindowIcons(window_icon, app_icon);
+}
+
+void NativeWidgetWin::InitModalType(ui::ModalType modal_type) {
+ message_handler_->InitModalType(modal_type);
+}
+
+gfx::Rect NativeWidgetWin::GetWindowBoundsInScreen() const {
+ gfx::Rect bounds_in_pixels = message_handler_->GetWindowBoundsInScreen();
+ return ui::win::ScreenToDIPRect(bounds_in_pixels);
+}
+
+gfx::Rect NativeWidgetWin::GetClientAreaBoundsInScreen() const {
+ gfx::Rect bounds_in_pixels = message_handler_->GetClientAreaBoundsInScreen();
+ return ui::win::ScreenToDIPRect(bounds_in_pixels);
+}
+
+gfx::Rect NativeWidgetWin::GetRestoredBounds() const {
+ gfx::Rect bounds_in_pixels = message_handler_->GetRestoredBounds();
+ return ui::win::ScreenToDIPRect(bounds_in_pixels);
+}
+
+void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) {
+ float scale = ui::win::GetDeviceScaleFactor();
+ gfx::Rect bounds_in_pixels(
+ gfx::ToCeiledPoint(gfx::ScalePoint(bounds.origin(), scale)),
+ gfx::ToFlooredSize(gfx::ScaleSize(bounds.size(), scale)));
+ message_handler_->SetBounds(bounds_in_pixels);
+}
+
+void NativeWidgetWin::SetSize(const gfx::Size& size) {
+ message_handler_->SetSize(size);
+}
+
+void NativeWidgetWin::StackAbove(gfx::NativeView native_view) {
+ message_handler_->StackAbove(native_view);
+}
+
+void NativeWidgetWin::StackAtTop() {
+ message_handler_->StackAtTop();
+}
+
+void NativeWidgetWin::StackBelow(gfx::NativeView native_view) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetWin::SetShape(gfx::NativeRegion region) {
+ message_handler_->SetRegion(region);
+}
+
+void NativeWidgetWin::Close() {
+ message_handler_->Close();
+}
+
+void NativeWidgetWin::CloseNow() {
+ message_handler_->CloseNow();
+}
+
+void NativeWidgetWin::Show() {
+ message_handler_->Show();
+}
+
+void NativeWidgetWin::Hide() {
+ message_handler_->Hide();
+}
+
+void NativeWidgetWin::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ gfx::Rect pixel_bounds = ui::win::DIPToScreenRect(restored_bounds);
+ message_handler_->ShowMaximizedWithBounds(pixel_bounds);
+}
+
+void NativeWidgetWin::ShowWithWindowState(ui::WindowShowState show_state) {
+ message_handler_->ShowWindowWithState(show_state);
+}
+
+bool NativeWidgetWin::IsVisible() const {
+ return message_handler_->IsVisible();
+}
+
+void NativeWidgetWin::Activate() {
+ message_handler_->Activate();
+}
+
+void NativeWidgetWin::Deactivate() {
+ message_handler_->Deactivate();
+}
+
+bool NativeWidgetWin::IsActive() const {
+ return message_handler_->IsActive();
+}
+
+void NativeWidgetWin::SetAlwaysOnTop(bool on_top) {
+ message_handler_->SetAlwaysOnTop(on_top);
+}
+
+void NativeWidgetWin::Maximize() {
+ message_handler_->Maximize();
+}
+
+void NativeWidgetWin::Minimize() {
+ message_handler_->Minimize();
+}
+
+bool NativeWidgetWin::IsMaximized() const {
+ return message_handler_->IsMaximized();
+}
+
+bool NativeWidgetWin::IsMinimized() const {
+ return message_handler_->IsMinimized();
+}
+
+void NativeWidgetWin::Restore() {
+ message_handler_->Restore();
+}
+
+void NativeWidgetWin::SetFullscreen(bool fullscreen) {
+ message_handler_->fullscreen_handler()->SetFullscreen(fullscreen);
+}
+
+void NativeWidgetWin::SetMetroSnapFullscreen(bool metro_snap) {
+ message_handler_->fullscreen_handler()->SetMetroSnap(metro_snap);
+}
+
+bool NativeWidgetWin::IsFullscreen() const {
+ return message_handler_->fullscreen_handler()->fullscreen();
+}
+
+bool NativeWidgetWin::IsInMetroSnapMode() const {
+ return message_handler_->fullscreen_handler()->metro_snap();
+}
+
+void NativeWidgetWin::SetCanUpdateLayeredWindow(bool can_update) {
+ message_handler_->set_can_update_layered_window(can_update);
+}
+
+void NativeWidgetWin::SetOpacity(unsigned char opacity) {
+ message_handler_->SetOpacity(static_cast<BYTE>(opacity));
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void NativeWidgetWin::SetUseDragFrame(bool use_drag_frame) {
+ if (use_drag_frame) {
+ // Make the frame slightly transparent during the drag operation.
+ drag_frame_saved_window_style_ = GetWindowLong(GetNativeView(), GWL_STYLE);
+ drag_frame_saved_window_ex_style_ =
+ GetWindowLong(GetNativeView(), GWL_EXSTYLE);
+ SetWindowLong(GetNativeView(), GWL_EXSTYLE,
+ drag_frame_saved_window_ex_style_ | WS_EX_LAYERED);
+ // Remove the captions tyle so the window doesn't have window controls for a
+ // more "transparent" look.
+ SetWindowLong(GetNativeView(), GWL_STYLE,
+ drag_frame_saved_window_style_ & ~WS_CAPTION);
+ SetLayeredWindowAttributes(GetNativeView(), RGB(0xFF, 0xFF, 0xFF),
+ kDragFrameWindowAlpha, LWA_ALPHA);
+ } else {
+ SetWindowLong(GetNativeView(), GWL_STYLE, drag_frame_saved_window_style_);
+ SetWindowLong(GetNativeView(), GWL_EXSTYLE,
+ drag_frame_saved_window_ex_style_);
+ }
+}
+
+void NativeWidgetWin::FlashFrame(bool flash) {
+ message_handler_->FlashFrame(flash);
+}
+
+void NativeWidgetWin::RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ views::RunShellDrag(NULL, data, location, operation, source);
+}
+
+void NativeWidgetWin::SchedulePaintInRect(const gfx::Rect& rect) {
+ gfx::Rect pixel_rect = ui::win::DIPToScreenRect(rect);
+ message_handler_->SchedulePaintInRect(pixel_rect);
+}
+
+void NativeWidgetWin::SetCursor(gfx::NativeCursor cursor) {
+ message_handler_->SetCursor(cursor);
+}
+
+bool NativeWidgetWin::IsMouseEventsEnabled() const {
+ return true;
+}
+
+void NativeWidgetWin::ClearNativeFocus() {
+ message_handler_->ClearNativeFocus();
+}
+
+gfx::Rect NativeWidgetWin::GetWorkAreaBoundsInScreen() const {
+ return ui::win::ScreenToDIPRect(
+ gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
+ GetNativeView()).work_area());
+}
+
+void NativeWidgetWin::SetInactiveRenderingDisabled(bool value) {
+}
+
+Widget::MoveLoopResult NativeWidgetWin::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) {
+ return message_handler_->RunMoveLoop(drag_offset) ?
+ Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
+}
+
+void NativeWidgetWin::EndMoveLoop() {
+ message_handler_->EndMoveLoop();
+}
+
+void NativeWidgetWin::SetVisibilityChangedAnimationsEnabled(bool value) {
+ message_handler_->SetVisibilityChangedAnimationsEnabled(value);
+}
+
+ui::NativeTheme* NativeWidgetWin::GetNativeTheme() const {
+ return ui::NativeTheme::instance();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, NativeWidget implementation:
+
+ui::EventHandler* NativeWidgetWin::GetEventHandler() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, protected:
+
+void NativeWidgetWin::OnFinalMessage(HWND window) {
+ // We don't destroy props in WM_DESTROY as we may still get messages after
+ // WM_DESTROY that assume the properties are still valid (such as WM_CLOSE).
+ props_.clear();
+ delegate_->OnNativeWidgetDestroyed();
+ if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ delete this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, protected:
+
+HWNDMessageHandler* NativeWidgetWin::GetMessageHandler() {
+ return message_handler_.get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, HWNDMessageHandlerDelegate implementation:
+
+bool NativeWidgetWin::IsWidgetWindow() const {
+ // We don't NULL check GetWidget()->non_client_view() here because this
+ // function can be called before the widget is fully constructed.
+ return has_non_client_view_;
+}
+
+bool NativeWidgetWin::IsUsingCustomFrame() const {
+ return !GetWidget()->ShouldUseNativeFrame();
+}
+
+void NativeWidgetWin::SchedulePaint() {
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void NativeWidgetWin::EnableInactiveRendering() {
+ delegate_->EnableInactiveRendering();
+}
+
+bool NativeWidgetWin::IsInactiveRenderingDisabled() {
+ return delegate_->IsInactiveRenderingDisabled();
+}
+
+bool NativeWidgetWin::CanResize() const {
+ return GetWidget()->widget_delegate()->CanResize();
+}
+
+bool NativeWidgetWin::CanMaximize() const {
+ return GetWidget()->widget_delegate()->CanMaximize();
+}
+
+bool NativeWidgetWin::CanActivate() const {
+ return delegate_->CanActivate();
+}
+
+bool NativeWidgetWin::WidgetSizeIsClientSize() const {
+ const Widget* widget = GetWidget()->GetTopLevelWidget();
+ return IsZoomed(GetNativeView()) ||
+ (widget && widget->ShouldUseNativeFrame());
+}
+
+bool NativeWidgetWin::CanSaveFocus() const {
+ return GetWidget()->is_top_level();
+}
+
+void NativeWidgetWin::SaveFocusOnDeactivate() {
+ GetWidget()->GetFocusManager()->StoreFocusedView(true);
+}
+
+void NativeWidgetWin::RestoreFocusOnActivate() {
+ // Mysteriously, this only appears to be needed support restoration of focus
+ // to a child hwnd when restoring its top level window from the minimized
+ // state. If we don't do this, then ::SetFocus() to that child HWND returns
+ // ERROR_INVALID_PARAMETER, despite both HWNDs being of the same thread.
+ // See http://crbug.com/125976 and
+ // chrome/browser/ui/views/native_widget_win_interactive_uitest.cc .
+ {
+ // Since this is a synthetic reset, we don't need to tell anyone about it.
+ AutoNativeNotificationDisabler disabler;
+ GetWidget()->GetFocusManager()->ClearFocus();
+ }
+ RestoreFocusOnEnable();
+}
+
+void NativeWidgetWin::RestoreFocusOnEnable() {
+ GetWidget()->GetFocusManager()->RestoreFocusedView();
+}
+
+bool NativeWidgetWin::IsModal() const {
+ return delegate_->IsModal();
+}
+
+int NativeWidgetWin::GetInitialShowState() const {
+ return SW_SHOWNORMAL;
+}
+
+bool NativeWidgetWin::WillProcessWorkAreaChange() const {
+ return GetWidget()->widget_delegate()->WillProcessWorkAreaChange();
+}
+
+int NativeWidgetWin::GetNonClientComponent(const gfx::Point& point) const {
+ gfx::Point point_in_dip = ui::win::ScreenToDIPPoint(point);
+ return delegate_->GetNonClientComponent(point_in_dip);
+}
+
+void NativeWidgetWin::GetWindowMask(const gfx::Size& size, gfx::Path* path) {
+ if (GetWidget()->non_client_view())
+ GetWidget()->non_client_view()->GetWindowMask(size, path);
+}
+
+bool NativeWidgetWin::GetClientAreaInsets(gfx::Insets* insets) const {
+ return false;
+}
+
+void NativeWidgetWin::GetMinMaxSize(gfx::Size* min_size,
+ gfx::Size* max_size) const {
+ *min_size = ui::win::ScreenToDIPSize(delegate_->GetMinimumSize());
+ *max_size = ui::win::ScreenToDIPSize(delegate_->GetMaximumSize());
+}
+
+gfx::Size NativeWidgetWin::GetRootViewSize() const {
+ gfx::Size pixel_size = GetWidget()->GetRootView()->size();
+ return ui::win::ScreenToDIPSize(pixel_size);
+}
+
+void NativeWidgetWin::ResetWindowControls() {
+ GetWidget()->non_client_view()->ResetWindowControls();
+}
+
+void NativeWidgetWin::PaintLayeredWindow(gfx::Canvas* canvas) {
+ GetWidget()->GetRootView()->Paint(canvas);
+}
+
+InputMethod* NativeWidgetWin::GetInputMethod() {
+ return GetWidget()->GetInputMethodDirect();
+}
+
+gfx::NativeViewAccessible NativeWidgetWin::GetNativeViewAccessible() {
+ return GetWidget()->GetRootView()->GetNativeViewAccessible();
+}
+
+bool NativeWidgetWin::ShouldHandleSystemCommands() const {
+ return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
+}
+
+void NativeWidgetWin::HandleAppDeactivated() {
+ if (IsInactiveRenderingDisabled()) {
+ delegate_->EnableInactiveRendering();
+ } else {
+ // TODO(pkotwicz): Remove need for SchedulePaint(). crbug.com/165841
+ View* non_client_view = GetWidget()->non_client_view();
+ if (non_client_view)
+ non_client_view->SchedulePaint();
+ }
+}
+
+void NativeWidgetWin::HandleActivationChanged(bool active) {
+ delegate_->OnNativeWidgetActivationChanged(active);
+}
+
+bool NativeWidgetWin::HandleAppCommand(short command) {
+ // We treat APPCOMMAND ids as an extension of our command namespace, and just
+ // let the delegate figure out what to do...
+ return GetWidget()->widget_delegate() &&
+ GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
+}
+
+void NativeWidgetWin::HandleCancelMode() {
+}
+
+void NativeWidgetWin::HandleCaptureLost() {
+ delegate_->OnMouseCaptureLost();
+}
+
+void NativeWidgetWin::HandleClose() {
+ GetWidget()->Close();
+}
+
+bool NativeWidgetWin::HandleCommand(int command) {
+ return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
+}
+
+void NativeWidgetWin::HandleAccelerator(const ui::Accelerator& accelerator) {
+ GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
+}
+
+void NativeWidgetWin::HandleCreate() {
+ // TODO(beng): much of this could/should maybe move to HWNDMessageHandler.
+
+ SetNativeWindowProperty(kNativeWidgetKey, this);
+ CHECK_EQ(this, GetNativeWidgetForNativeView(GetNativeView()));
+
+ props_.push_back(ui::SetWindowSupportsRerouteMouseWheel(GetNativeView()));
+
+ drop_target_ = new DropTargetWin(
+ static_cast<internal::RootView*>(GetWidget()->GetRootView()));
+
+ // Windows special DWM window frame requires a special tooltip manager so
+ // that window controls in Chrome windows don't flicker when you move your
+ // mouse over them. See comment in aero_tooltip_manager.h.
+ Widget* widget = GetWidget()->GetTopLevelWidget();
+ if (widget && widget->ShouldUseNativeFrame()) {
+ tooltip_manager_.reset(new AeroTooltipManager(GetWidget()));
+ } else {
+ tooltip_manager_.reset(new TooltipManagerWin(GetWidget()));
+ }
+ if (!tooltip_manager_->Init()) {
+ // There was a problem creating the TooltipManager. Common error is 127.
+ // See 82193 for details.
+ LOG_GETLASTERROR(WARNING) << "tooltip creation failed, disabling tooltips";
+ tooltip_manager_.reset();
+ }
+
+ delegate_->OnNativeWidgetCreated(true);
+}
+
+void NativeWidgetWin::HandleDestroying() {
+ delegate_->OnNativeWidgetDestroying();
+ if (drop_target_.get()) {
+ RevokeDragDrop(GetNativeView());
+ drop_target_ = NULL;
+ }
+}
+
+void NativeWidgetWin::HandleDestroyed() {
+ OnFinalMessage(GetNativeView());
+}
+
+bool NativeWidgetWin::HandleInitialFocus() {
+ return GetWidget()->SetInitialFocus();
+}
+
+void NativeWidgetWin::HandleDisplayChange() {
+ GetWidget()->widget_delegate()->OnDisplayChanged();
+}
+
+void NativeWidgetWin::HandleBeginWMSizeMove() {
+ delegate_->OnNativeWidgetBeginUserBoundsChange();
+}
+
+void NativeWidgetWin::HandleEndWMSizeMove() {
+ delegate_->OnNativeWidgetEndUserBoundsChange();
+}
+
+void NativeWidgetWin::HandleMove() {
+ delegate_->OnNativeWidgetMove();
+}
+
+void NativeWidgetWin::HandleWorkAreaChanged() {
+ GetWidget()->widget_delegate()->OnWorkAreaChanged();
+}
+
+void NativeWidgetWin::HandleVisibilityChanged(bool visible) {
+ delegate_->OnNativeWidgetVisibilityChanged(visible);
+}
+
+void NativeWidgetWin::HandleClientSizeChanged(const gfx::Size& new_size) {
+ gfx::Size size_in_dip = ui::win::ScreenToDIPSize(new_size);
+ delegate_->OnNativeWidgetSizeChanged(size_in_dip);
+}
+
+void NativeWidgetWin::HandleFrameChanged() {
+ // Replace the frame and layout the contents.
+ GetWidget()->non_client_view()->UpdateFrame(true);
+}
+
+void NativeWidgetWin::HandleNativeFocus(HWND last_focused_window) {
+ delegate_->OnNativeFocus(last_focused_window);
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->OnFocus();
+}
+
+void NativeWidgetWin::HandleNativeBlur(HWND focused_window) {
+ delegate_->OnNativeBlur(focused_window);
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->OnBlur();
+}
+
+bool NativeWidgetWin::HandleMouseEvent(const ui::MouseEvent& event) {
+ static gfx::Transform scale_transform(
+ 1/ui::win::GetDeviceScaleFactor(), 0.0,
+ 0.0, 1/ui::win::GetDeviceScaleFactor(),
+ 0.0, 0.0);
+ if (event.IsMouseWheelEvent()) {
+ ui::MouseWheelEvent dpi_event(
+ static_cast<const ui::MouseWheelEvent&>(event));
+ dpi_event.UpdateForRootTransform(scale_transform);
+ delegate_->OnMouseEvent(&dpi_event);
+ return dpi_event.handled();
+ } else if (event.IsMouseEvent()) {
+ CHECK(!event.IsScrollEvent()); // Scroll events don't happen in Windows.
+ ui::MouseEvent dpi_event(event);
+ if (!(dpi_event.flags() & ui::EF_IS_NON_CLIENT))
+ dpi_event.UpdateForRootTransform(scale_transform);
+ delegate_->OnMouseEvent(&dpi_event);
+ return dpi_event.handled();
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool NativeWidgetWin::HandleKeyEvent(const ui::KeyEvent& event) {
+ delegate_->OnKeyEvent(const_cast<ui::KeyEvent*>(&event));
+ return event.handled();
+}
+
+bool NativeWidgetWin::HandleUntranslatedKeyEvent(const ui::KeyEvent& event) {
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->DispatchKeyEvent(event);
+ return !!input_method;
+}
+
+bool NativeWidgetWin::HandleTouchEvent(const ui::TouchEvent& event) {
+ NOTREACHED() << "Touch events are not supported";
+ return false;
+}
+
+bool NativeWidgetWin::HandleIMEMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) {
+ InputMethod* input_method = GetInputMethod();
+ if (!input_method || input_method->IsMock()) {
+ *result = 0;
+ return false;
+ }
+
+ MSG msg = {};
+ msg.hwnd = message_handler_->hwnd();
+ msg.message = message;
+ msg.wParam = w_param;
+ msg.lParam = l_param;
+ return input_method->OnUntranslatedIMEMessage(msg, result);
+}
+
+void NativeWidgetWin::HandleInputLanguageChange(DWORD character_set,
+ HKL input_language_id) {
+ InputMethod* input_method = GetInputMethod();
+ if (input_method && !input_method->IsMock()) {
+ input_method->OnInputLocaleChanged();
+ }
+}
+
+bool NativeWidgetWin::HandlePaintAccelerated(const gfx::Rect& invalid_rect) {
+ gfx::Rect dpi_rect = ui::win::ScreenToDIPRect(invalid_rect);
+ return delegate_->OnNativeWidgetPaintAccelerated(dpi_rect);
+}
+
+void NativeWidgetWin::HandlePaint(gfx::Canvas* canvas) {
+ delegate_->OnNativeWidgetPaint(canvas);
+}
+
+bool NativeWidgetWin::HandleTooltipNotify(int w_param,
+ NMHDR* l_param,
+ LRESULT* l_result) {
+ // We can be sent this message before the tooltip manager is created, if a
+ // subclass overrides OnCreate and creates some kind of Windows control there
+ // that sends WM_NOTIFY messages.
+ if (tooltip_manager_.get()) {
+ bool handled;
+ *l_result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+ return handled;
+ }
+ return false;
+}
+
+void NativeWidgetWin::HandleTooltipMouseMove(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ if (tooltip_manager_.get())
+ tooltip_manager_->OnMouse(message, w_param, l_param);
+}
+
+bool NativeWidgetWin::PreHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) {
+ return false;
+}
+
+void NativeWidgetWin::PostHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, private:
+
+void NativeWidgetWin::SetInitParams(const Widget::InitParams& params) {
+ // Set non-style attributes.
+ ownership_ = params.ownership;
+
+ ConfigureWindowStyles(message_handler_.get(), params,
+ GetWidget()->widget_delegate(), delegate_);
+
+ has_non_client_view_ = Widget::RequiresNonClientView(params.type);
+ message_handler_->set_remove_standard_frame(params.remove_standard_frame);
+ message_handler_->set_use_system_default_icon(params.use_system_default_icon);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, public:
+
+// static
+void Widget::NotifyLocaleChanged() {
+ NOTIMPLEMENTED();
+}
+
+namespace {
+BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
+ Widget* widget = Widget::GetWidgetForNativeView(hwnd);
+ if (widget && widget->is_secondary_widget())
+ widget->Close();
+ return TRUE;
+}
+} // namespace
+
+// static
+void Widget::CloseAllSecondaryWidgets() {
+ EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0);
+}
+
+bool Widget::ConvertRect(const Widget* source,
+ const Widget* target,
+ gfx::Rect* rect) {
+ DCHECK(source);
+ DCHECK(target);
+ DCHECK(rect);
+
+ HWND source_hwnd = source->GetNativeView();
+ HWND target_hwnd = target->GetNativeView();
+ if (source_hwnd == target_hwnd)
+ return true;
+
+ RECT win_rect = ui::win::DIPToScreenRect(*rect).ToRECT();
+ if (::MapWindowPoints(source_hwnd, target_hwnd,
+ reinterpret_cast<LPPOINT>(&win_rect),
+ sizeof(RECT)/sizeof(POINT))) {
+ *rect = ui::win::ScreenToDIPRect(gfx::Rect(win_rect));
+ return true;
+ }
+ return false;
+}
+
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// internal::NativeWidgetPrivate, public:
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
+ internal::NativeWidgetDelegate* delegate) {
+ return new NativeWidgetWin(delegate);
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
+ gfx::NativeView native_view) {
+ return reinterpret_cast<NativeWidgetWin*>(
+ ViewProp::GetValue(native_view, kNativeWidgetKey));
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
+ gfx::NativeWindow native_window) {
+ return GetNativeWidgetForNativeView(native_window);
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
+ gfx::NativeView native_view) {
+ if (!native_view)
+ return NULL;
+
+ // First, check if the top-level window is a Widget.
+ HWND root = ::GetAncestor(native_view, GA_ROOT);
+ if (!root)
+ return NULL;
+
+ NativeWidgetPrivate* widget = GetNativeWidgetForNativeView(root);
+ if (widget)
+ return widget;
+
+ // Second, try to locate the last Widget window in the parent hierarchy.
+ HWND parent_hwnd = native_view;
+ // If we fail to find the native widget pointer for the root then it probably
+ // means that the root belongs to a different process in which case we walk up
+ // the native view chain looking for a parent window which corresponds to a
+ // valid native widget. We only do this if we fail to find the native widget
+ // for the current native view which means it is being destroyed.
+ if (!widget && !GetNativeWidgetForNativeView(native_view)) {
+ parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
+ if (!parent_hwnd)
+ return NULL;
+ }
+ NativeWidgetPrivate* parent_widget;
+ do {
+ parent_widget = GetNativeWidgetForNativeView(parent_hwnd);
+ if (parent_widget) {
+ widget = parent_widget;
+ parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
+ }
+ } while (parent_hwnd != NULL && parent_widget != NULL);
+
+ return widget;
+}
+
+// static
+void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
+ Widget::Widgets* children) {
+ if (!native_view)
+ return;
+
+ Widget* widget = Widget::GetWidgetForNativeView(native_view);
+ if (widget)
+ children->insert(widget);
+ EnumChildWindows(native_view, EnumerateChildWindowsForNativeWidgets,
+ reinterpret_cast<LPARAM>(children));
+}
+
+// static
+void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
+ gfx::NativeView new_parent) {
+ if (!native_view)
+ return;
+
+ HWND previous_parent = ::GetParent(native_view);
+ if (previous_parent == new_parent)
+ return;
+
+ Widget::Widgets widgets;
+ GetAllChildWidgets(native_view, &widgets);
+
+ // First notify all the widgets that they are being disassociated
+ // from their previous parent.
+ for (Widget::Widgets::iterator it = widgets.begin();
+ it != widgets.end(); ++it) {
+ // TODO(beng): Rename this notification to NotifyNativeViewChanging()
+ // and eliminate the bool parameter.
+ (*it)->NotifyNativeViewHierarchyChanged(false, previous_parent);
+ }
+
+ ::SetParent(native_view, new_parent);
+
+ // And now, notify them that they have a brand new parent.
+ for (Widget::Widgets::iterator it = widgets.begin();
+ it != widgets.end(); ++it) {
+ (*it)->NotifyNativeViewHierarchyChanged(true, new_parent);
+ }
+}
+
+// static
+bool NativeWidgetPrivate::IsMouseButtonDown() {
+ return (GetKeyState(VK_LBUTTON) & 0x80) ||
+ (GetKeyState(VK_RBUTTON) & 0x80) ||
+ (GetKeyState(VK_MBUTTON) & 0x80) ||
+ (GetKeyState(VK_XBUTTON1) & 0x80) ||
+ (GetKeyState(VK_XBUTTON2) & 0x80);
+}
+
+// static
+bool NativeWidgetPrivate::IsTouchDown() {
+ // This currently isn't necessary because we're not generating touch events on
+ // windows. When we do, this will need to be updated.
+ return false;
+}
+
+} // namespace internal
+
+} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_win.h b/chromium/ui/views/widget/native_widget_win.h
new file mode 100644
index 00000000000..81fa718ef41
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_win.h
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/win_util.h"
+#include "ui/base/win/window_impl.h"
+#include "ui/views/widget/native_widget_private.h"
+#include "ui/views/win/hwnd_message_handler_delegate.h"
+
+namespace ui {
+class Compositor;
+class ViewProp;
+}
+
+namespace gfx {
+class Canvas;
+class Font;
+class Rect;
+}
+
+namespace views {
+
+class DropTargetWin;
+class HWNDMessageHandler;
+class InputMethodDelegate;
+class RootView;
+class TooltipManagerWin;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// NativeWidgetWin
+// A Widget for a views hierarchy used to represent anything that can be
+// contained within an HWND, e.g. a control, a window, etc. Specializations
+// suitable for specific tasks, e.g. top level window, are derived from this.
+//
+// This Widget contains a RootView which owns the hierarchy of views within it.
+// As long as views are part of this tree, they will be deleted automatically
+// when the RootView is destroyed. If you remove a view from the tree, you are
+// then responsible for cleaning up after it.
+//
+///////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT NativeWidgetWin : public internal::NativeWidgetPrivate,
+ public HWNDMessageHandlerDelegate {
+ public:
+ explicit NativeWidgetWin(internal::NativeWidgetDelegate* delegate);
+ virtual ~NativeWidgetWin();
+
+ // Returns the system set window title font.
+ static gfx::Font GetWindowTitleFont();
+
+ // Show the window with the specified show command.
+ void Show(int show_state);
+
+ // Places the window in a pseudo-fullscreen mode where it looks and acts as
+ // like a fullscreen window except that it remains within the boundaries
+ // of the metro snap divider.
+ void SetMetroSnapFullscreen(bool metro_snap);
+ bool IsInMetroSnapMode() const;
+
+ void SetCanUpdateLayeredWindow(bool can_update);
+
+ // Overridden from internal::NativeWidgetPrivate:
+ virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
+ virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
+ virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual const Widget* GetWidget() const OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
+ virtual Widget* GetTopLevelWidget() OVERRIDE;
+ virtual const ui::Compositor* GetCompositor() const OVERRIDE;
+ virtual ui::Compositor* GetCompositor() OVERRIDE;
+ virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
+ virtual void ViewRemoved(View* view) OVERRIDE;
+ virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
+ virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
+ virtual TooltipManager* GetTooltipManager() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual InputMethod* CreateInputMethod() OVERRIDE;
+ virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const OVERRIDE;
+ virtual void SetWindowTitle(const string16& title) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void StackAbove(gfx::NativeView native_view) OVERRIDE;
+ virtual void StackAtTop() OVERRIDE;
+ virtual void StackBelow(gfx::NativeView native_view) OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion shape) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual void ShowWithWindowState(ui::WindowShowState show_state) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetUseDragFrame(bool use_drag_frame) OVERRIDE;
+ virtual void FlashFrame(bool flash) OVERRIDE;
+ virtual void RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual bool IsMouseEventsEnabled() const OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetInactiveRenderingDisabled(bool value) OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
+
+ // Overridden from NativeWidget:
+ virtual ui::EventHandler* GetEventHandler() OVERRIDE;
+
+ protected:
+ // Deletes this window as it is destroyed, override to provide different
+ // behavior.
+ virtual void OnFinalMessage(HWND window);
+
+ HWNDMessageHandler* GetMessageHandler();
+
+ // Overridden from HWNDMessageHandlerDelegate:
+ virtual bool IsWidgetWindow() const OVERRIDE;
+ virtual bool IsUsingCustomFrame() const OVERRIDE;
+ virtual void SchedulePaint() OVERRIDE;
+ virtual void EnableInactiveRendering() OVERRIDE;
+ virtual bool IsInactiveRenderingDisabled() OVERRIDE;
+ virtual bool CanResize() const OVERRIDE;
+ virtual bool CanMaximize() const OVERRIDE;
+ virtual bool CanActivate() const OVERRIDE;
+ virtual bool WidgetSizeIsClientSize() const OVERRIDE;
+ virtual bool CanSaveFocus() const OVERRIDE;
+ virtual void SaveFocusOnDeactivate() OVERRIDE;
+ virtual void RestoreFocusOnActivate() OVERRIDE;
+ virtual void RestoreFocusOnEnable() OVERRIDE;
+ virtual bool IsModal() const OVERRIDE;
+ virtual int GetInitialShowState() const OVERRIDE;
+ virtual bool WillProcessWorkAreaChange() const OVERRIDE;
+ virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
+ virtual void GetWindowMask(const gfx::Size& size, gfx::Path* path) OVERRIDE;
+ virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
+ virtual void GetMinMaxSize(gfx::Size* min_size,
+ gfx::Size* max_size) const OVERRIDE;
+ virtual gfx::Size GetRootViewSize() const OVERRIDE;
+ virtual void ResetWindowControls() OVERRIDE;
+ virtual void PaintLayeredWindow(gfx::Canvas* canvas) OVERRIDE;
+ virtual InputMethod* GetInputMethod() OVERRIDE;
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual bool ShouldHandleSystemCommands() const OVERRIDE;
+ virtual void HandleAppDeactivated() OVERRIDE;
+ virtual void HandleActivationChanged(bool active) OVERRIDE;
+ virtual bool HandleAppCommand(short command) OVERRIDE;
+ virtual void HandleCancelMode() OVERRIDE;
+ virtual void HandleCaptureLost() OVERRIDE;
+ virtual void HandleClose() OVERRIDE;
+ virtual bool HandleCommand(int command) OVERRIDE;
+ virtual void HandleAccelerator(const ui::Accelerator& accelerator) OVERRIDE;
+ virtual void HandleCreate() OVERRIDE;
+ virtual void HandleDestroying() OVERRIDE;
+ virtual void HandleDestroyed() OVERRIDE;
+ virtual bool HandleInitialFocus() OVERRIDE;
+ virtual void HandleDisplayChange() OVERRIDE;
+ virtual void HandleBeginWMSizeMove() OVERRIDE;
+ virtual void HandleEndWMSizeMove() OVERRIDE;
+ virtual void HandleMove() OVERRIDE;
+ virtual void HandleWorkAreaChanged() OVERRIDE;
+ virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
+ virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
+ virtual void HandleFrameChanged() OVERRIDE;
+ virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE;
+ virtual void HandleNativeBlur(HWND focused_window) OVERRIDE;
+ virtual bool HandleMouseEvent(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool HandleKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual bool HandleUntranslatedKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual bool HandleTouchEvent(const ui::TouchEvent& event) OVERRIDE;
+ virtual bool HandleIMEMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) OVERRIDE;
+ virtual void HandleInputLanguageChange(DWORD character_set,
+ HKL input_language_id) OVERRIDE;
+ virtual bool HandlePaintAccelerated(const gfx::Rect& invalid_rect) OVERRIDE;
+ virtual void HandlePaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual bool HandleTooltipNotify(int w_param,
+ NMHDR* l_param,
+ LRESULT* l_result) OVERRIDE;
+ virtual void HandleTooltipMouseMove(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+ virtual bool PreHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) OVERRIDE;
+ virtual void PostHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+
+ // The TooltipManager. This is NULL if there is a problem creating the
+ // underlying tooltip window.
+ // WARNING: RootView's destructor calls into the TooltipManager. As such, this
+ // must be destroyed AFTER root_view_.
+ scoped_ptr<TooltipManagerWin> tooltip_manager_;
+
+ scoped_refptr<DropTargetWin> drop_target_;
+
+ private:
+ typedef ScopedVector<ui::ViewProp> ViewProps;
+
+ void SetInitParams(const Widget::InitParams& params);
+
+ // A delegate implementation that handles events received here.
+ // See class documentation for Widget in widget.h for a note about ownership.
+ internal::NativeWidgetDelegate* delegate_;
+
+ // See class documentation for Widget in widget.h for a note about ownership.
+ Widget::InitParams::Ownership ownership_;
+
+ ViewProps props_;
+
+ // The window styles before we modified them for the drag frame appearance.
+ DWORD drag_frame_saved_window_style_;
+ DWORD drag_frame_saved_window_ex_style_;
+
+ // True if the widget is going to have a non_client_view. We cache this value
+ // rather than asking the Widget for the non_client_view so that we know at
+ // Init time, before the Widget has created the NonClientView.
+ bool has_non_client_view_;
+
+ scoped_ptr<HWNDMessageHandler> message_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
diff --git a/chromium/ui/views/widget/native_widget_win_unittest.cc b/chromium/ui/views/widget/native_widget_win_unittest.cc
new file mode 100644
index 00000000000..6a84ca06d70
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_win_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/native_widget_win.h"
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/win/scoped_ole_initializer.h"
+
+namespace views {
+namespace {
+
+class NativeWidgetWinTest : public testing::Test {
+ public:
+ NativeWidgetWinTest() {}
+ ~NativeWidgetWinTest() {}
+
+ virtual void TearDown() {
+ // Flush the message loop because we have pending release tasks
+ // and these tasks if un-executed would upset Valgrind.
+ RunPendingMessages();
+ }
+
+ // Create a simple widget win. The caller is responsible for taking ownership
+ // of the returned value.
+ NativeWidgetWin* CreateNativeWidgetWin();
+
+ void RunPendingMessages() {
+ message_loop_.RunUntilIdle();
+ }
+
+ private:
+ base::MessageLoopForUI message_loop_;
+ ui::ScopedOleInitializer ole_initializer_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetWinTest);
+};
+
+NativeWidgetWin* NativeWidgetWinTest::CreateNativeWidgetWin() {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget->Init(params);
+ return static_cast<NativeWidgetWin*>(widget.release()->native_widget());
+}
+
+TEST_F(NativeWidgetWinTest, ZoomWindow) {
+ scoped_ptr<NativeWidgetWin> window(CreateNativeWidgetWin());
+ ShowWindow(window->GetNativeView(), SW_HIDE);
+ EXPECT_FALSE(window->IsActive());
+ ShowWindow(window->GetNativeView(), SW_MAXIMIZE);
+ EXPECT_TRUE(IsZoomed(window->GetNativeView()));
+ window->CloseNow();
+}
+
+TEST_F(NativeWidgetWinTest, SetBoundsForZoomedWindow) {
+ scoped_ptr<NativeWidgetWin> window(CreateNativeWidgetWin());
+ ShowWindow(window->GetNativeView(), SW_MAXIMIZE);
+ EXPECT_TRUE(IsZoomed(window->GetNativeView()));
+
+ // Create another window, so that it will be active.
+ scoped_ptr<NativeWidgetWin> window2(CreateNativeWidgetWin());
+ ShowWindow(window2->GetNativeView(), SW_MAXIMIZE);
+ EXPECT_TRUE(window2->IsActive());
+ EXPECT_FALSE(window->IsActive());
+
+ // Verify that setting the bounds of a zoomed window will unzoom it and not
+ // cause it to be activated.
+ window->SetBounds(gfx::Rect(50, 50, 650, 650));
+ EXPECT_FALSE(IsZoomed(window->GetNativeView()));
+ EXPECT_FALSE(window->IsActive());
+
+ // Cleanup.
+ window->CloseNow();
+ window2->CloseNow();
+}
+
+} // namespace
+} // namespace views
diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc
new file mode 100644
index 00000000000..b304c520b97
--- /dev/null
+++ b/chromium/ui/views/widget/root_view.cc
@@ -0,0 +1,707 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/root_view.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/events/event.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/focus/view_storage.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_deletion_observer.h"
+
+namespace views {
+namespace internal {
+
+namespace {
+
+enum EventType {
+ EVENT_ENTER,
+ EVENT_EXIT
+};
+
+class MouseEnterExitEvent : public ui::MouseEvent {
+ public:
+ MouseEnterExitEvent(const ui::MouseEvent& event, ui::EventType type)
+ : ui::MouseEvent(event,
+ static_cast<View*>(NULL),
+ static_cast<View*>(NULL)) {
+ DCHECK(type == ui::ET_MOUSE_ENTERED ||
+ type == ui::ET_MOUSE_EXITED);
+ SetType(type);
+ }
+
+ virtual ~MouseEnterExitEvent() {}
+};
+
+} // namespace
+
+// static
+const char RootView::kViewClassName[] = "RootView";
+
+////////////////////////////////////////////////////////////////////////////////
+// RootView, public:
+
+// Creation and lifetime -------------------------------------------------------
+
+RootView::RootView(Widget* widget)
+ : widget_(widget),
+ mouse_pressed_handler_(NULL),
+ mouse_move_handler_(NULL),
+ last_click_handler_(NULL),
+ explicit_mouse_handler_(false),
+ last_mouse_event_flags_(0),
+ last_mouse_event_x_(-1),
+ last_mouse_event_y_(-1),
+ touch_pressed_handler_(NULL),
+ gesture_handler_(NULL),
+ scroll_gesture_handler_(NULL),
+ focus_search_(this, false, false),
+ focus_traversable_parent_(NULL),
+ focus_traversable_parent_view_(NULL),
+ event_dispatch_target_(NULL) {
+}
+
+RootView::~RootView() {
+ // If we have children remove them explicitly so to make sure a remove
+ // notification is sent for each one of them.
+ if (has_children())
+ RemoveAllChildViews(true);
+}
+
+// Tree operations -------------------------------------------------------------
+
+void RootView::SetContentsView(View* contents_view) {
+ DCHECK(contents_view && GetWidget()->native_widget()) <<
+ "Can't be called until after the native widget is created!";
+ // The ContentsView must be set up _after_ the window is created so that its
+ // Widget pointer is valid.
+ SetLayoutManager(new FillLayout);
+ if (has_children())
+ RemoveAllChildViews(true);
+ AddChildView(contents_view);
+
+ // Force a layout now, since the attached hierarchy won't be ready for the
+ // containing window's bounds. Note that we call Layout directly rather than
+ // calling the widget's size changed handler, since the RootView's bounds may
+ // not have changed, which will cause the Layout not to be done otherwise.
+ Layout();
+}
+
+View* RootView::GetContentsView() {
+ return child_count() > 0 ? child_at(0) : NULL;
+}
+
+void RootView::NotifyNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view) {
+ PropagateNativeViewHierarchyChanged(attached, native_view, this);
+}
+
+// Input -----------------------------------------------------------------------
+
+void RootView::DispatchKeyEvent(ui::KeyEvent* event) {
+ View* v = NULL;
+ if (GetFocusManager()) // NULL in unittests.
+ v = GetFocusManager()->GetFocusedView();
+ // Special case to handle right-click context menus triggered by the
+ // keyboard.
+ if (v && v->enabled() && ((event->key_code() == ui::VKEY_APPS) ||
+ (event->key_code() == ui::VKEY_F10 && event->IsShiftDown()))) {
+ v->ShowContextMenu(v->GetKeyboardContextMenuLocation(),
+ ui::MENU_SOURCE_KEYBOARD);
+ event->StopPropagation();
+ return;
+ }
+
+ for (; v && v != this && !event->handled(); v = v->parent())
+ DispatchEventToTarget(v, event);
+}
+
+void RootView::DispatchScrollEvent(ui::ScrollEvent* event) {
+ for (View* v = GetEventHandlerForPoint(event->location());
+ v && v != this && !event->stopped_propagation(); v = v->parent()) {
+ DispatchEventToTarget(v, event);
+ }
+
+ if (event->handled() || event->type() != ui::ET_SCROLL)
+ return;
+
+ // Convert unprocessed scroll events into mouse-wheel events.
+ ui::MouseWheelEvent wheel(*event);
+ if (OnMouseWheel(wheel))
+ event->SetHandled();
+}
+
+void RootView::DispatchTouchEvent(ui::TouchEvent* event) {
+ // TODO: this looks all wrong. On a TOUCH_PRESSED we should figure out the
+ // view and target that view with all touches with the same id until the
+ // release (or keep it if captured).
+
+ // If touch_pressed_handler_ is non null, we are currently processing
+ // a touch down on the screen situation. In that case we send the
+ // event to touch_pressed_handler_
+
+ if (touch_pressed_handler_) {
+ ui::TouchEvent touch_event(*event, static_cast<View*>(this),
+ touch_pressed_handler_);
+ DispatchEventToTarget(touch_pressed_handler_, &touch_event);
+ if (touch_event.handled())
+ event->SetHandled();
+ if (touch_event.stopped_propagation())
+ event->StopPropagation();
+ return;
+ }
+
+ // Walk up the tree until we find a view that wants the touch event.
+ for (touch_pressed_handler_ = GetEventHandlerForPoint(event->location());
+ touch_pressed_handler_ && (touch_pressed_handler_ != this);
+ touch_pressed_handler_ = touch_pressed_handler_->parent()) {
+ if (!touch_pressed_handler_->enabled()) {
+ // Disabled views eat events but are treated as not handled.
+ break;
+ }
+
+ // See if this view wants to handle the touch
+ ui::TouchEvent touch_event(*event, static_cast<View*>(this),
+ touch_pressed_handler_);
+ DispatchEventToTarget(touch_pressed_handler_, &touch_event);
+ if (touch_event.handled())
+ event->SetHandled();
+ if (touch_event.stopped_propagation())
+ event->StopPropagation();
+
+ // The view could have removed itself from the tree when handling
+ // OnTouchEvent(). So handle as per OnMousePressed. NB: we
+ // assume that the RootView itself cannot be so removed.
+ if (!touch_pressed_handler_)
+ break;
+
+ // The touch event wasn't processed. Go up the view hierarchy and dispatch
+ // the touch event.
+ if (!event->handled())
+ continue;
+
+ // If a View consumed the event, that means future touch-events should go to
+ // that View. If the event wasn't consumed, then reset the handler.
+ if (!event->stopped_propagation())
+ touch_pressed_handler_ = NULL;
+
+ return;
+ }
+
+ // Reset touch_pressed_handler_ to indicate that no processing is occurring.
+ touch_pressed_handler_ = NULL;
+
+ return;
+}
+
+void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
+ if (gesture_handler_) {
+ // |gesture_handler_| (or |scroll_gesture_handler_|) can be deleted during
+ // processing.
+ View* handler = scroll_gesture_handler_ &&
+ (event->IsScrollGestureEvent() || event->IsFlingScrollEvent()) ?
+ scroll_gesture_handler_ : gesture_handler_;
+ ui::GestureEvent handler_event(*event, static_cast<View*>(this), handler);
+ DispatchEventToTarget(handler, &handler_event);
+
+ if (event->type() == ui::ET_GESTURE_END &&
+ event->details().touch_points() <= 1) {
+ // In case a drag was in progress, reset all the handlers. Otherwise, just
+ // reset the gesture handler.
+ if (gesture_handler_ == mouse_pressed_handler_)
+ SetMouseHandler(NULL);
+ else
+ gesture_handler_ = NULL;
+ }
+
+ if (scroll_gesture_handler_ &&
+ (event->type() == ui::ET_GESTURE_SCROLL_END ||
+ event->type() == ui::ET_SCROLL_FLING_START)) {
+ scroll_gesture_handler_ = NULL;
+ }
+
+ if (handler_event.stopped_propagation()) {
+ event->StopPropagation();
+ return;
+ } else if (handler_event.handled()) {
+ event->SetHandled();
+ return;
+ }
+
+ if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN &&
+ !scroll_gesture_handler_) {
+ // Some view started processing gesture events, however it does not
+ // process scroll-gesture events. In such case, we allow the event to
+ // bubble up, and install a different scroll-gesture handler different
+ // from the default gesture handler.
+ for (scroll_gesture_handler_ = gesture_handler_->parent();
+ scroll_gesture_handler_ && scroll_gesture_handler_ != this;
+ scroll_gesture_handler_ = scroll_gesture_handler_->parent()) {
+ ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
+ scroll_gesture_handler_);
+ DispatchEventToTarget(scroll_gesture_handler_, &gesture_event);
+ if (gesture_event.stopped_propagation()) {
+ event->StopPropagation();
+ return;
+ } else if (gesture_event.handled()) {
+ event->SetHandled();
+ return;
+ }
+ }
+ scroll_gesture_handler_ = NULL;
+ }
+
+ return;
+ }
+
+ // If there was no handler for a SCROLL_BEGIN event, then subsequent scroll
+ // events are not dispatched to any views.
+ switch (event->type()) {
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ case ui::ET_GESTURE_SCROLL_END:
+ case ui::ET_SCROLL_FLING_START:
+ return;
+ default:
+ break;
+ }
+
+ // Walk up the tree until we find a view that wants the gesture event.
+ for (gesture_handler_ = GetEventHandlerForPoint(event->location());
+ gesture_handler_ && (gesture_handler_ != this);
+ gesture_handler_ = gesture_handler_->parent()) {
+ if (!gesture_handler_->enabled()) {
+ // Disabled views eat events but are treated as not handled.
+ return;
+ }
+
+ // See if this view wants to handle the Gesture.
+ ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
+ gesture_handler_);
+ DispatchEventToTarget(gesture_handler_, &gesture_event);
+
+ // The view could have removed itself from the tree when handling
+ // OnGestureEvent(). So handle as per OnMousePressed. NB: we
+ // assume that the RootView itself cannot be so removed.
+ if (!gesture_handler_)
+ return;
+
+ if (gesture_event.handled()) {
+ if (gesture_event.type() == ui::ET_GESTURE_SCROLL_BEGIN)
+ scroll_gesture_handler_ = gesture_handler_;
+ if (gesture_event.stopped_propagation())
+ event->StopPropagation();
+ else
+ event->SetHandled();
+ return;
+ }
+
+ // The gesture event wasn't processed. Go up the view hierarchy and
+ // dispatch the gesture event.
+ }
+
+ gesture_handler_ = NULL;
+}
+
+// Focus -----------------------------------------------------------------------
+
+void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
+ DCHECK(focus_traversable != this);
+ focus_traversable_parent_ = focus_traversable;
+}
+
+void RootView::SetFocusTraversableParentView(View* view) {
+ focus_traversable_parent_view_ = view;
+}
+
+// System events ---------------------------------------------------------------
+
+void RootView::ThemeChanged() {
+ View::PropagateThemeChanged();
+}
+
+void RootView::LocaleChanged() {
+ View::PropagateLocaleChanged();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RootView, FocusTraversable implementation:
+
+FocusSearch* RootView::GetFocusSearch() {
+ return &focus_search_;
+}
+
+FocusTraversable* RootView::GetFocusTraversableParent() {
+ return focus_traversable_parent_;
+}
+
+View* RootView::GetFocusTraversableParentView() {
+ return focus_traversable_parent_view_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RootView, View overrides:
+
+const Widget* RootView::GetWidget() const {
+ return widget_;
+}
+
+Widget* RootView::GetWidget() {
+ return const_cast<Widget*>(const_cast<const RootView*>(this)->GetWidget());
+}
+
+bool RootView::IsDrawn() const {
+ return visible();
+}
+
+const char* RootView::GetClassName() const {
+ return kViewClassName;
+}
+
+void RootView::SchedulePaintInRect(const gfx::Rect& rect) {
+ if (layer()) {
+ layer()->SchedulePaint(rect);
+ } else {
+ gfx::Rect xrect = ConvertRectToParent(rect);
+ gfx::Rect invalid_rect = gfx::IntersectRects(GetLocalBounds(), xrect);
+ if (!invalid_rect.IsEmpty())
+ widget_->SchedulePaintInRect(invalid_rect);
+ }
+}
+
+bool RootView::OnMousePressed(const ui::MouseEvent& event) {
+ UpdateCursor(event);
+ SetMouseLocationAndFlags(event);
+
+ // If mouse_pressed_handler_ is non null, we are currently processing
+ // a pressed -> drag -> released session. In that case we send the
+ // event to mouse_pressed_handler_
+ if (mouse_pressed_handler_) {
+ ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
+ mouse_pressed_handler_);
+ drag_info_.Reset();
+ DispatchEventToTarget(mouse_pressed_handler_, &mouse_pressed_event);
+ return true;
+ }
+ DCHECK(!explicit_mouse_handler_);
+
+ bool hit_disabled_view = false;
+ // Walk up the tree until we find a view that wants the mouse event.
+ for (mouse_pressed_handler_ = GetEventHandlerForPoint(event.location());
+ mouse_pressed_handler_ && (mouse_pressed_handler_ != this);
+ mouse_pressed_handler_ = mouse_pressed_handler_->parent()) {
+ DVLOG(1) << "OnMousePressed testing "
+ << mouse_pressed_handler_->GetClassName();
+ if (!mouse_pressed_handler_->enabled()) {
+ // Disabled views should eat events instead of propagating them upwards.
+ hit_disabled_view = true;
+ break;
+ }
+
+ // See if this view wants to handle the mouse press.
+ ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
+ mouse_pressed_handler_);
+
+ // Remove the double-click flag if the handler is different than the
+ // one which got the first click part of the double-click.
+ if (mouse_pressed_handler_ != last_click_handler_)
+ mouse_pressed_event.set_flags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK);
+
+ drag_info_.Reset();
+ {
+ WidgetDeletionObserver widget_deletion_observer(widget_);
+ DispatchEventToTarget(mouse_pressed_handler_, &mouse_pressed_event);
+ if (!widget_deletion_observer.IsWidgetAlive())
+ return mouse_pressed_event.handled();
+ }
+
+ // The view could have removed itself from the tree when handling
+ // OnMousePressed(). In this case, the removal notification will have
+ // reset mouse_pressed_handler_ to NULL out from under us. Detect this
+ // case and stop. (See comments in view.h.)
+ //
+ // NOTE: Don't return true here, because we don't want the frame to
+ // forward future events to us when there's no handler.
+ if (!mouse_pressed_handler_)
+ break;
+
+ // If the view handled the event, leave mouse_pressed_handler_ set and
+ // return true, which will cause subsequent drag/release events to get
+ // forwarded to that view.
+ if (mouse_pressed_event.handled()) {
+ last_click_handler_ = mouse_pressed_handler_;
+ DVLOG(1) << "OnMousePressed handled by "
+ << mouse_pressed_handler_->GetClassName();
+ return true;
+ }
+ }
+
+ // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
+ mouse_pressed_handler_ = NULL;
+
+ // In the event that a double-click is not handled after traversing the
+ // entire hierarchy (even as a single-click when sent to a different view),
+ // it must be marked as handled to avoid anything happening from default
+ // processing if it the first click-part was handled by us.
+ if (last_click_handler_ && (event.flags() & ui::EF_IS_DOUBLE_CLICK))
+ hit_disabled_view = true;
+
+ last_click_handler_ = NULL;
+ return hit_disabled_view;
+}
+
+bool RootView::OnMouseDragged(const ui::MouseEvent& event) {
+ if (mouse_pressed_handler_) {
+ SetMouseLocationAndFlags(event);
+
+ ui::MouseEvent mouse_event(event, static_cast<View*>(this),
+ mouse_pressed_handler_);
+ DispatchEventToTarget(mouse_pressed_handler_, &mouse_event);
+ }
+ return false;
+}
+
+void RootView::OnMouseReleased(const ui::MouseEvent& event) {
+ UpdateCursor(event);
+
+ if (mouse_pressed_handler_) {
+ ui::MouseEvent mouse_released(event, static_cast<View*>(this),
+ mouse_pressed_handler_);
+ // We allow the view to delete us from the event dispatch callback. As such,
+ // configure state such that we're done first, then call View.
+ View* mouse_pressed_handler = mouse_pressed_handler_;
+ SetMouseHandler(NULL);
+ DispatchEventToTarget(mouse_pressed_handler, &mouse_released);
+ // WARNING: we may have been deleted.
+ }
+}
+
+void RootView::OnMouseCaptureLost() {
+ // TODO: this likely needs to reset touch handler too.
+
+ if (mouse_pressed_handler_ || gesture_handler_) {
+ // Synthesize a release event for UpdateCursor.
+ if (mouse_pressed_handler_) {
+ gfx::Point last_point(last_mouse_event_x_, last_mouse_event_y_);
+ ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED,
+ last_point, last_point,
+ last_mouse_event_flags_);
+ UpdateCursor(release_event);
+ }
+ // We allow the view to delete us from OnMouseCaptureLost. As such,
+ // configure state such that we're done first, then call View.
+ View* mouse_pressed_handler = mouse_pressed_handler_;
+ View* gesture_handler = gesture_handler_;
+ SetMouseHandler(NULL);
+ if (mouse_pressed_handler)
+ mouse_pressed_handler->OnMouseCaptureLost();
+ else
+ gesture_handler->OnMouseCaptureLost();
+ // WARNING: we may have been deleted.
+ }
+}
+
+void RootView::OnMouseMoved(const ui::MouseEvent& event) {
+ View* v = GetEventHandlerForPoint(event.location());
+ // Find the first enabled view, or the existing move handler, whichever comes
+ // first. The check for the existing handler is because if a view becomes
+ // disabled while handling moves, it's wrong to suddenly send ET_MOUSE_EXITED
+ // and ET_MOUSE_ENTERED events, because the mouse hasn't actually exited yet.
+ while (v && !v->enabled() && (v != mouse_move_handler_))
+ v = v->parent();
+ if (v && v != this) {
+ if (v != mouse_move_handler_) {
+ if (mouse_move_handler_ != NULL &&
+ (!mouse_move_handler_->notify_enter_exit_on_child() ||
+ !mouse_move_handler_->Contains(v))) {
+ MouseEnterExitEvent exit(event, ui::ET_MOUSE_EXITED);
+ DispatchEventToTarget(mouse_move_handler_, &exit);
+ NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
+ mouse_move_handler_, v);
+ }
+ View* old_handler = mouse_move_handler_;
+ mouse_move_handler_ = v;
+ if (!mouse_move_handler_->notify_enter_exit_on_child() ||
+ !mouse_move_handler_->Contains(old_handler)) {
+ MouseEnterExitEvent entered(event, ui::ET_MOUSE_ENTERED);
+ entered.ConvertLocationToTarget(static_cast<View*>(this),
+ mouse_move_handler_);
+ DispatchEventToTarget(mouse_move_handler_, &entered);
+ NotifyEnterExitOfDescendant(entered, ui::ET_MOUSE_ENTERED, v,
+ old_handler);
+ }
+ }
+ ui::MouseEvent moved_event(event, static_cast<View*>(this),
+ mouse_move_handler_);
+ mouse_move_handler_->OnMouseMoved(moved_event);
+ if (!(moved_event.flags() & ui::EF_IS_NON_CLIENT))
+ widget_->SetCursor(mouse_move_handler_->GetCursor(moved_event));
+ } else if (mouse_move_handler_ != NULL) {
+ MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
+ DispatchEventToTarget(mouse_move_handler_, &exited);
+ NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
+ mouse_move_handler_, v);
+ // On Aura the non-client area extends slightly outside the root view for
+ // some windows. Let the non-client cursor handling code set the cursor
+ // as we do above.
+ if (!(event.flags() & ui::EF_IS_NON_CLIENT))
+ widget_->SetCursor(gfx::kNullCursor);
+ mouse_move_handler_ = NULL;
+ }
+}
+
+void RootView::OnMouseExited(const ui::MouseEvent& event) {
+ if (mouse_move_handler_ != NULL) {
+ MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
+ DispatchEventToTarget(mouse_move_handler_, &exited);
+ NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
+ mouse_move_handler_, NULL);
+ mouse_move_handler_ = NULL;
+ }
+}
+
+bool RootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
+ for (View* v = GetEventHandlerForPoint(event.location());
+ v && v != this && !event.handled(); v = v->parent())
+ DispatchEventToTarget(v, const_cast<ui::MouseWheelEvent*>(&event));
+ return event.handled();
+}
+
+void RootView::SetMouseHandler(View* new_mh) {
+ // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well.
+ explicit_mouse_handler_ = (new_mh != NULL);
+ mouse_pressed_handler_ = new_mh;
+ gesture_handler_ = new_mh;
+ scroll_gesture_handler_ = new_mh;
+ drag_info_.Reset();
+}
+
+void RootView::GetAccessibleState(ui::AccessibleViewState* state) {
+ state->name = widget_->widget_delegate()->GetAccessibleWindowTitle();
+ state->role = widget_->widget_delegate()->GetAccessibleWindowRole();
+}
+
+void RootView::UpdateParentLayer() {
+ if (layer())
+ ReparentLayer(gfx::Vector2d(GetMirroredX(), y()), widget_->GetLayer());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RootView, protected:
+
+void RootView::ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) {
+ widget_->ViewHierarchyChanged(details);
+
+ if (!details.is_add) {
+ if (!explicit_mouse_handler_ && mouse_pressed_handler_ == details.child)
+ mouse_pressed_handler_ = NULL;
+ if (mouse_move_handler_ == details.child)
+ mouse_move_handler_ = NULL;
+ if (touch_pressed_handler_ == details.child)
+ touch_pressed_handler_ = NULL;
+ if (gesture_handler_ == details.child)
+ gesture_handler_ = NULL;
+ if (scroll_gesture_handler_ == details.child)
+ scroll_gesture_handler_ = NULL;
+ if (event_dispatch_target_ == details.child)
+ event_dispatch_target_ = NULL;
+ }
+}
+
+void RootView::VisibilityChanged(View* /*starting_from*/, bool is_visible) {
+ if (!is_visible) {
+ // When the root view is being hidden (e.g. when widget is minimized)
+ // handlers are reset, so that after it is reshown, events are not captured
+ // by old handlers.
+ mouse_pressed_handler_ = NULL;
+ mouse_move_handler_ = NULL;
+ touch_pressed_handler_ = NULL;
+ gesture_handler_ = NULL;
+ scroll_gesture_handler_ = NULL;
+ event_dispatch_target_ = NULL;
+ }
+}
+
+void RootView::OnPaint(gfx::Canvas* canvas) {
+ if (!layer() || !layer()->fills_bounds_opaquely())
+ canvas->DrawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);
+
+ // TODO (pkotwicz): Remove this once we switch over to Aura desktop.
+ // This is needed so that we can set the background behind the RWHV when the
+ // RWHV is not visible. Not needed once there is a view between the RootView
+ // and RWHV.
+ View::OnPaint(canvas);
+}
+
+gfx::Vector2d RootView::CalculateOffsetToAncestorWithLayer(
+ ui::Layer** layer_parent) {
+ gfx::Vector2d offset(View::CalculateOffsetToAncestorWithLayer(layer_parent));
+ if (!layer() && layer_parent)
+ *layer_parent = widget_->GetLayer();
+ return offset;
+}
+
+View::DragInfo* RootView::GetDragInfo() {
+ return &drag_info_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RootView, private:
+
+// Input -----------------------------------------------------------------------
+
+void RootView::UpdateCursor(const ui::MouseEvent& event) {
+ if (!(event.flags() & ui::EF_IS_NON_CLIENT)) {
+ View* v = GetEventHandlerForPoint(event.location());
+ ui::MouseEvent me(event, static_cast<View*>(this), v);
+ widget_->SetCursor(v->GetCursor(me));
+ }
+}
+
+void RootView::SetMouseLocationAndFlags(const ui::MouseEvent& event) {
+ last_mouse_event_flags_ = event.flags();
+ last_mouse_event_x_ = event.x();
+ last_mouse_event_y_ = event.y();
+}
+
+void RootView::DispatchEventToTarget(View* target, ui::Event* event) {
+ View* old_target = event_dispatch_target_;
+ event_dispatch_target_ = target;
+ if (DispatchEvent(target, event))
+ event_dispatch_target_ = old_target;
+}
+
+void RootView::NotifyEnterExitOfDescendant(const ui::MouseEvent& event,
+ ui::EventType type,
+ View* view,
+ View* sibling) {
+ for (View* p = view->parent(); p; p = p->parent()) {
+ if (!p->notify_enter_exit_on_child())
+ continue;
+ if (sibling && p->Contains(sibling))
+ break;
+ // It is necessary to recreate the notify-event for each dispatch, since one
+ // of the callbacks can mark the event as handled, and that would cause
+ // incorrect event dispatch.
+ MouseEnterExitEvent notify_event(event, type);
+ DispatchEventToTarget(p, &notify_event);
+ }
+}
+
+bool RootView::CanDispatchToTarget(ui::EventTarget* target) {
+ return event_dispatch_target_ == target;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/widget/root_view.h b/chromium/ui/views/widget/root_view.h
new file mode 100644
index 00000000000..b89ab8fe8eb
--- /dev/null
+++ b/chromium/ui/views/widget/root_view.h
@@ -0,0 +1,226 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_ROOT_VIEW_H_
+#define UI_VIEWS_WIDGET_ROOT_VIEW_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "ui/base/events/event_dispatcher.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/focus/focus_search.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+namespace test {
+class WidgetTest;
+}
+
+class Widget;
+
+// This is a views-internal API and should not be used externally.
+// Widget exposes this object as a View*.
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// RootView class
+//
+// The RootView is the root of a View hierarchy. A RootView is attached to a
+// Widget. The Widget is responsible for receiving events from the host
+// environment, converting them to views-compatible events and then forwarding
+// them to the RootView for propagation into the View hierarchy.
+//
+// A RootView can have only one child, called its "Contents View" which is
+// sized to fill the bounds of the RootView (and hence the client area of the
+// Widget). Call SetContentsView() after the associated Widget has been
+// initialized to attach the contents view to the RootView.
+// TODO(beng): Enforce no other callers to AddChildView/tree functions by
+// overriding those methods as private here.
+// TODO(beng): Clean up API further, make Widget a friend.
+// TODO(sky): We don't really want to export this class.
+//
+class VIEWS_EXPORT RootView : public View,
+ public FocusTraversable,
+ public ui::EventDispatcherDelegate {
+ public:
+ static const char kViewClassName[];
+
+ // Creation and lifetime -----------------------------------------------------
+ explicit RootView(Widget* widget);
+ virtual ~RootView();
+
+ // Tree operations -----------------------------------------------------------
+
+ // Sets the "contents view" of the RootView. This is the single child view
+ // that is responsible for laying out the contents of the widget.
+ void SetContentsView(View* contents_view);
+ View* GetContentsView();
+
+ // Called when parent of the host changed.
+ void NotifyNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view);
+
+ // Input ---------------------------------------------------------------------
+
+ // Process a key event. Send the event to the focused view and up the focus
+ // path, and finally to the default keyboard handler, until someone consumes
+ // it. Returns whether anyone consumed the event.
+ void DispatchKeyEvent(ui::KeyEvent* event);
+ void DispatchScrollEvent(ui::ScrollEvent* event);
+ void DispatchTouchEvent(ui::TouchEvent* event);
+ virtual void DispatchGestureEvent(ui::GestureEvent* event);
+
+ // Focus ---------------------------------------------------------------------
+
+ // Used to set the FocusTraversable parent after the view has been created
+ // (typically when the hierarchy changes and this RootView is added/removed).
+ virtual void SetFocusTraversableParent(FocusTraversable* focus_traversable);
+
+ // Used to set the View parent after the view has been created.
+ virtual void SetFocusTraversableParentView(View* view);
+
+ // System events -------------------------------------------------------------
+
+ // Public API for broadcasting theme change notifications to this View
+ // hierarchy.
+ void ThemeChanged();
+
+ // Public API for broadcasting locale change notifications to this View
+ // hierarchy.
+ void LocaleChanged();
+
+ // Overridden from FocusTraversable:
+ virtual FocusSearch* GetFocusSearch() OVERRIDE;
+ virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
+ virtual View* GetFocusTraversableParentView() OVERRIDE;
+
+ // Overridden from View:
+ virtual const Widget* GetWidget() const OVERRIDE;
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual bool IsDrawn() const OVERRIDE;
+ virtual const char* GetClassName() const OVERRIDE;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseCaptureLost() OVERRIDE;
+ virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseWheel(const ui::MouseWheelEvent& event) OVERRIDE;
+ virtual void SetMouseHandler(View* new_mouse_handler) OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void UpdateParentLayer() OVERRIDE;
+
+ protected:
+ // Overridden from View:
+ virtual void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) OVERRIDE;
+ virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::Vector2d CalculateOffsetToAncestorWithLayer(
+ ui::Layer** layer_parent) OVERRIDE;
+ virtual View::DragInfo* GetDragInfo() OVERRIDE;
+
+ private:
+ friend class ::views::View;
+ friend class ::views::Widget;
+ friend class ::views::test::WidgetTest;
+
+ // Input ---------------------------------------------------------------------
+
+ // Update the cursor given a mouse event. This is called by non mouse_move
+ // event handlers to honor the cursor desired by views located under the
+ // cursor during drag operations. The location of the mouse should be in the
+ // current coordinate system (i.e. any necessary transformation should be
+ // applied to the point prior to calling this).
+ void UpdateCursor(const ui::MouseEvent& event);
+
+ // Updates the last_mouse_* fields from e. The location of the mouse should be
+ // in the current coordinate system (i.e. any necessary transformation should
+ // be applied to the point prior to calling this).
+ void SetMouseLocationAndFlags(const ui::MouseEvent& event);
+
+ void DispatchEventToTarget(View* target, ui::Event* event);
+
+ // |view| is the view receiving |event|. This function sends the event to all
+ // the Views up the hierarchy that has |notify_enter_exit_on_child_| flag
+ // turned on, but does not contain |sibling|.
+ void NotifyEnterExitOfDescendant(const ui::MouseEvent& event,
+ ui::EventType type,
+ View* view,
+ View* sibling);
+
+ // Overridden from ui::EventDispatcherDelegate:
+ virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE;
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Tree operations -----------------------------------------------------------
+
+ // The host Widget
+ Widget* widget_;
+
+ // Input ---------------------------------------------------------------------
+
+ // The view currently handing down - drag - up
+ View* mouse_pressed_handler_;
+
+ // The view currently handling enter / exit
+ View* mouse_move_handler_;
+
+ // The last view to handle a mouse click, so that we can determine if
+ // a double-click lands on the same view as its single-click part.
+ View* last_click_handler_;
+
+ // true if mouse_pressed_handler_ has been explicitly set
+ bool explicit_mouse_handler_;
+
+ // Last position/flag of a mouse press/drag. Used if capture stops and we need
+ // to synthesize a release.
+ int last_mouse_event_flags_;
+ int last_mouse_event_x_;
+ int last_mouse_event_y_;
+
+ // The view currently handling touch events.
+ View* touch_pressed_handler_;
+
+ // The view currently handling gesture events. When set, this handler receives
+ // all gesture events, except when there is an event handler for the specific
+ // gesture (e.g. scroll).
+ View* gesture_handler_;
+
+ // The view currently handling scroll gesture events.
+ View* scroll_gesture_handler_;
+
+ // Focus ---------------------------------------------------------------------
+
+ // The focus search algorithm.
+ FocusSearch focus_search_;
+
+ // Whether this root view belongs to the current active window.
+ // bool activated_;
+
+ // The parent FocusTraversable, used for focus traversal.
+ FocusTraversable* focus_traversable_parent_;
+
+ // The View that contains this RootView. This is used when we have RootView
+ // wrapped inside native components, and is used for the focus traversal.
+ View* focus_traversable_parent_view_;
+
+ View* event_dispatch_target_;
+
+ // Drag and drop -------------------------------------------------------------
+
+ // Tracks drag state for a view.
+ View::DragInfo drag_info_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RootView);
+};
+
+} // namespace internal
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_ROOT_VIEW_H_
diff --git a/chromium/ui/views/widget/tooltip_manager.cc b/chromium/ui/views/widget/tooltip_manager.cc
new file mode 100644
index 00000000000..bfcbf02b47d
--- /dev/null
+++ b/chromium/ui/views/widget/tooltip_manager.cc
@@ -0,0 +1,65 @@
+// 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/views/widget/tooltip_manager.h"
+
+#include <vector>
+
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/text/text_elider.h"
+
+namespace {
+
+// Maximum number of characters we allow in a tooltip.
+const size_t kMaxTooltipLength = 1024;
+
+// Maximum number of lines we allow in the tooltip.
+const size_t kMaxLines = 6;
+
+} // namespace
+
+namespace views {
+
+// static
+void TooltipManager::TrimTooltipToFit(string16* text,
+ int* max_width,
+ int* line_count,
+ int x,
+ int y,
+ gfx::NativeView context) {
+ *max_width = 0;
+ *line_count = 0;
+
+ // Clamp the tooltip length to kMaxTooltipLength so that we don't
+ // accidentally DOS the user with a mega tooltip.
+ if (text->length() > kMaxTooltipLength)
+ *text = text->substr(0, kMaxTooltipLength);
+
+ // Determine the available width for the tooltip.
+ int available_width = GetMaxWidth(x, y, context);
+
+ // Split the string into at most kMaxLines lines.
+ std::vector<string16> lines;
+ base::SplitString(*text, '\n', &lines);
+ if (lines.size() > kMaxLines)
+ lines.resize(kMaxLines);
+ *line_count = static_cast<int>(lines.size());
+
+ // Format each line to fit.
+ gfx::Font font = GetDefaultFont();
+ string16 result;
+ for (std::vector<string16>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ string16 elided_text =
+ ui::ElideText(*i, font, available_width, ui::ELIDE_AT_END);
+ *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
+ if (!result.empty())
+ result.push_back('\n');
+ result.append(elided_text);
+ }
+ *text = result;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/tooltip_manager.h b/chromium/ui/views/widget/tooltip_manager.h
new file mode 100644
index 00000000000..f8601dd6ae3
--- /dev/null
+++ b/chromium/ui/views/widget/tooltip_manager.h
@@ -0,0 +1,71 @@
+// 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_VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+#define UI_VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Font;
+} // namespace gfx
+
+namespace views {
+
+class View;
+
+// TooltipManager takes care of the wiring to support tooltips for Views. You
+// almost never need to interact directly with TooltipManager, rather look to
+// the various tooltip methods on View.
+class VIEWS_EXPORT TooltipManager {
+ public:
+ // Returns the height of tooltips. This should only be invoked from within
+ // GetTooltipTextOrigin.
+ static int GetTooltipHeight();
+
+ // Returns the default font used by tooltips.
+ static gfx::Font GetDefaultFont();
+
+ // Returns the maximum width of the tooltip. |x| and |y| give the location
+ // the tooltip is to be displayed on in screen coordinates. |context| is
+ // used to determine which gfx::Screen should be used.
+ static int GetMaxWidth(int x, int y, gfx::NativeView context);
+
+ TooltipManager() {}
+ virtual ~TooltipManager() {}
+
+ // Notification that the view hierarchy has changed in some way.
+ virtual void UpdateTooltip() = 0;
+
+ // Invoked when the tooltip text changes for the specified views.
+ virtual void TooltipTextChanged(View* view) = 0;
+
+ // Invoked when toolbar icon gets focus.
+ virtual void ShowKeyboardTooltip(View* view) = 0;
+
+ // Invoked when toolbar loses focus.
+ virtual void HideKeyboardTooltip() = 0;
+
+ protected:
+ // Trims the tooltip to fit, setting |text| to the clipped result,
+ // |max_width| to the width (in pixels) of the clipped text and |line_count|
+ // to the number of lines of text in the tooltip. |x| and |y| give the
+ // location of the tooltip in screen coordinates. |context| is used to
+ // determine which gfx::Screen should be used.
+ static void TrimTooltipToFit(string16* text,
+ int* max_width,
+ int* line_count,
+ int x,
+ int y,
+ gfx::NativeView context);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_TOOLTIP_MANAGER_H_
diff --git a/chromium/ui/views/widget/tooltip_manager_aura.cc b/chromium/ui/views/widget/tooltip_manager_aura.cc
new file mode 100644
index 00000000000..f7a47613fc3
--- /dev/null
+++ b/chromium/ui/views/widget/tooltip_manager_aura.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/tooltip_manager_aura.h"
+
+#include "base/logging.h"
+#include "ui/aura/client/tooltip_client.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+// static
+int TooltipManager::GetTooltipHeight() {
+ // Not used for linux and chromeos.
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+// static
+gfx::Font TooltipManager::GetDefaultFont() {
+ return ui::ResourceBundle::GetSharedInstance().GetFont(
+ ui::ResourceBundle::BaseFont);
+}
+
+// static
+int TooltipManager::GetMaxWidth(int x, int y, gfx::NativeView context) {
+ gfx::Rect monitor_bounds =
+ gfx::Screen::GetScreenFor(context)->GetDisplayNearestPoint(
+ gfx::Point(x, y)).bounds();
+ return (monitor_bounds.width() + 1) / 2;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TooltipManagerAura public:
+
+TooltipManagerAura::TooltipManagerAura(aura::Window* window, Widget* widget)
+ : window_(window),
+ widget_(widget) {
+ aura::client::SetTooltipText(window_, &tooltip_text_);
+}
+
+TooltipManagerAura::~TooltipManagerAura() {
+ aura::client::SetTooltipText(window_, NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TooltipManagerAura, TooltipManager implementation:
+
+void TooltipManagerAura::UpdateTooltip() {
+ aura::RootWindow* root_window = window_->GetRootWindow();
+ if (aura::client::GetTooltipClient(root_window)) {
+ gfx::Point view_point = root_window->GetLastMouseLocationInRoot();
+ aura::Window::ConvertPointToTarget(root_window, window_, &view_point);
+ View* view = GetViewUnderPoint(view_point);
+ UpdateTooltipForTarget(view, view_point, root_window);
+ }
+}
+
+void TooltipManagerAura::TooltipTextChanged(View* view) {
+ aura::RootWindow* root_window = window_->GetRootWindow();
+ if (aura::client::GetTooltipClient(root_window)) {
+ gfx::Point view_point = root_window->GetLastMouseLocationInRoot();
+ aura::Window::ConvertPointToTarget(root_window, window_, &view_point);
+ View* target = GetViewUnderPoint(view_point);
+ if (target != view)
+ return;
+ UpdateTooltipForTarget(view, view_point, root_window);
+ }
+}
+
+void TooltipManagerAura::ShowKeyboardTooltip(View* view) {
+ NOTREACHED();
+}
+
+void TooltipManagerAura::HideKeyboardTooltip() {
+ NOTREACHED();
+}
+
+View* TooltipManagerAura::GetViewUnderPoint(const gfx::Point& point) {
+ View* root_view = widget_->GetRootView();
+ if (root_view)
+ return root_view->GetTooltipHandlerForPoint(point);
+ return NULL;
+}
+
+void TooltipManagerAura::UpdateTooltipForTarget(View* target,
+ const gfx::Point& point,
+ aura::RootWindow* root_window) {
+ if (target) {
+ gfx::Point view_point = point;
+ View::ConvertPointFromWidget(target, &view_point);
+ string16 new_tooltip_text;
+ if (!target->GetTooltipText(view_point, &new_tooltip_text))
+ tooltip_text_.clear();
+ else
+ tooltip_text_ = new_tooltip_text;
+ } else {
+ tooltip_text_.clear();
+ }
+ aura::client::GetTooltipClient(root_window)->UpdateTooltip(window_);
+}
+
+} // namespace views.
diff --git a/chromium/ui/views/widget/tooltip_manager_aura.h b/chromium/ui/views/widget/tooltip_manager_aura.h
new file mode 100644
index 00000000000..dd4b5ade439
--- /dev/null
+++ b/chromium/ui/views/widget/tooltip_manager_aura.h
@@ -0,0 +1,49 @@
+// 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_VIEWS_WIDGET_TOOLTIP_MANAGER_AURA_H_
+#define UI_VIEWS_WIDGET_TOOLTIP_MANAGER_AURA_H_
+
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "ui/gfx/point.h"
+#include "ui/views/widget/tooltip_manager.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+}
+
+namespace views {
+
+class Widget;
+
+// TooltipManager implementation for Aura.
+class TooltipManagerAura : public TooltipManager {
+ public:
+ TooltipManagerAura(aura::Window* window, Widget* widget);
+ virtual ~TooltipManagerAura();
+
+ // TooltipManager.
+ virtual void UpdateTooltip() OVERRIDE;
+ virtual void TooltipTextChanged(View* view) OVERRIDE;
+ virtual void ShowKeyboardTooltip(View* view) OVERRIDE;
+ virtual void HideKeyboardTooltip() OVERRIDE;
+
+ private:
+ View* GetViewUnderPoint(const gfx::Point& point);
+ void UpdateTooltipForTarget(View* target,
+ const gfx::Point& point,
+ aura::RootWindow* root_window);
+
+ aura::Window* window_;
+ Widget* widget_;
+ string16 tooltip_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(TooltipManagerAura);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_TOOLTIP_MANAGER_AURA_H_
diff --git a/chromium/ui/views/widget/tooltip_manager_win.cc b/chromium/ui/views/widget/tooltip_manager_win.cc
new file mode 100644
index 00000000000..fa0ad45d711
--- /dev/null
+++ b/chromium/ui/views/widget/tooltip_manager_win.cc
@@ -0,0 +1,399 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/tooltip_manager_win.h"
+
+#include <windowsx.h>
+
+#include <limits>
+
+#include "base/bind.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_util.h"
+#include "base/win/scoped_hdc.h"
+#include "base/win/scoped_select_object.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/win/dpi.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/base/win/scoped_set_map_mode.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/monitor_win.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+static int tooltip_height_ = 0;
+
+// Default timeout for the tooltip displayed using keyboard.
+// Timeout is measured in milliseconds.
+static const int kDefaultTimeout = 4000;
+
+// static
+int TooltipManager::GetTooltipHeight() {
+ DCHECK_GT(tooltip_height_, 0);
+ return tooltip_height_;
+}
+
+static gfx::Font DetermineDefaultFont() {
+ HWND window = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ if (!window)
+ return gfx::Font();
+ HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
+ gfx::Font font = hfont ? gfx::Font(hfont) : gfx::Font();
+ DestroyWindow(window);
+ return font;
+}
+
+// static
+gfx::Font TooltipManager::GetDefaultFont() {
+ static gfx::Font* font = NULL;
+ if (!font)
+ font = new gfx::Font(DetermineDefaultFont());
+ return *font;
+}
+
+// static
+int TooltipManager::GetMaxWidth(int x, int y, gfx::NativeView context) {
+ gfx::Rect monitor_bounds =
+ gfx::Screen::GetScreenFor(context)->GetDisplayNearestPoint(
+ gfx::Point(x, y)).bounds();
+ // Allow the tooltip to be almost as wide as the screen.
+ // Otherwise, we would truncate important text, since we're not word-wrapping
+ // the text onto multiple lines.
+ return monitor_bounds.width() == 0 ? 800 : monitor_bounds.width() - 30;
+}
+
+TooltipManagerWin::TooltipManagerWin(Widget* widget)
+ : widget_(widget),
+ tooltip_hwnd_(NULL),
+ last_mouse_pos_(-1, -1),
+ tooltip_showing_(false),
+ last_tooltip_view_(NULL),
+ last_view_out_of_sync_(false),
+ tooltip_width_(0),
+ keyboard_tooltip_hwnd_(NULL),
+ keyboard_tooltip_factory_(this) {
+ DCHECK(widget);
+ DCHECK(widget->GetNativeView());
+}
+
+TooltipManagerWin::~TooltipManagerWin() {
+ if (tooltip_hwnd_)
+ DestroyWindow(tooltip_hwnd_);
+ if (keyboard_tooltip_hwnd_)
+ DestroyWindow(keyboard_tooltip_hwnd_);
+}
+
+bool TooltipManagerWin::Init() {
+ DCHECK(!tooltip_hwnd_);
+ // Create the tooltip control.
+ tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+ GetParent(), NULL, NULL, NULL);
+ if (!tooltip_hwnd_)
+ return false;
+
+ l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+
+ // This effectively turns off clipping of tooltips. We need this otherwise
+ // multi-line text (\r\n) won't work right. The size doesn't really matter
+ // (just as long as its bigger than the monitor's width) as we clip to the
+ // screen size before rendering.
+ SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+ std::numeric_limits<int16>::max());
+
+ // Add one tool that is used for all tooltips.
+ toolinfo_.cbSize = sizeof(toolinfo_);
+ toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
+ toolinfo_.hwnd = GetParent();
+ toolinfo_.uId = reinterpret_cast<UINT_PTR>(GetParent());
+ // Setting this tells windows to call GetParent() back (using a WM_NOTIFY
+ // message) for the actual tooltip contents.
+ toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+ toolinfo_.lpReserved = NULL;
+ SetRectEmpty(&toolinfo_.rect);
+ SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+ return true;
+}
+
+gfx::NativeView TooltipManagerWin::GetParent() {
+ return widget_->GetNativeView();
+}
+
+void TooltipManagerWin::UpdateTooltip() {
+ // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
+ // This doesn't update the view under the mouse immediately as it may cause
+ // timing problems.
+ last_view_out_of_sync_ = true;
+ last_tooltip_view_ = NULL;
+ // Hide the tooltip.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+}
+
+void TooltipManagerWin::TooltipTextChanged(View* view) {
+ if (view == last_tooltip_view_)
+ UpdateTooltip(last_mouse_pos_);
+}
+
+LRESULT TooltipManagerWin::OnNotify(int w_param,
+ NMHDR* l_param,
+ bool* handled) {
+ *handled = false;
+ if (l_param->hwndFrom == tooltip_hwnd_ && keyboard_tooltip_hwnd_ == NULL) {
+ switch (l_param->code) {
+ case TTN_GETDISPINFO: {
+ if (last_view_out_of_sync_) {
+ // View under the mouse is out of sync, determine it now.
+ View* root_view = widget_->GetRootView();
+ last_tooltip_view_ =
+ root_view->GetTooltipHandlerForPoint(last_mouse_pos_);
+ last_view_out_of_sync_ = false;
+ }
+ // Tooltip control is asking for the tooltip to display.
+ NMTTDISPINFOW* tooltip_info =
+ reinterpret_cast<NMTTDISPINFOW*>(l_param);
+ // Initialize the string, if we have a valid tooltip the string will
+ // get reset below.
+ tooltip_info->szText[0] = TEXT('\0');
+ tooltip_text_.clear();
+ tooltip_info->lpszText = NULL;
+ clipped_text_.clear();
+ if (last_tooltip_view_ != NULL) {
+ tooltip_text_.clear();
+ // Mouse is over a View, ask the View for its tooltip.
+ gfx::Point view_loc = last_mouse_pos_;
+ View::ConvertPointToTarget(widget_->GetRootView(),
+ last_tooltip_view_, &view_loc);
+ if (last_tooltip_view_->GetTooltipText(view_loc, &tooltip_text_) &&
+ !tooltip_text_.empty()) {
+ // View has a valid tip, copy it into TOOLTIPINFO.
+ clipped_text_ = tooltip_text_;
+ gfx::Point screen_loc = last_mouse_pos_;
+ View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
+ TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
+ screen_loc.x(), screen_loc.y(),
+ widget_->GetNativeView());
+ // Adjust the clipped tooltip text for locale direction.
+ base::i18n::AdjustStringForLocaleDirection(&clipped_text_);
+ tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
+ } else {
+ tooltip_text_.clear();
+ }
+ }
+ *handled = true;
+ return 0;
+ }
+ case TTN_POP:
+ tooltip_showing_ = false;
+ *handled = true;
+ return 0;
+ case TTN_SHOW: {
+ *handled = true;
+ tooltip_showing_ = true;
+ // The tooltip is about to show, allow the view to position it
+ gfx::Point text_origin;
+ if (tooltip_height_ == 0)
+ tooltip_height_ = CalcTooltipHeight();
+ gfx::Point view_loc = last_mouse_pos_;
+ View::ConvertPointToTarget(widget_->GetRootView(),
+ last_tooltip_view_, &view_loc);
+ if (last_tooltip_view_->GetTooltipTextOrigin(view_loc, &text_origin) &&
+ SetTooltipPosition(text_origin.x(), text_origin.y())) {
+ // Return true, otherwise the rectangle we specified is ignored.
+ return TRUE;
+ }
+ return 0;
+ }
+ default:
+ // Fall through.
+ break;
+ }
+ }
+ return 0;
+}
+
+bool TooltipManagerWin::SetTooltipPosition(int text_x, int text_y) {
+ // NOTE: this really only tests that the y location fits on screen, but that
+ // is good enough for our usage.
+
+ // Calculate the bounds the tooltip will get.
+ gfx::Point view_loc;
+ View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
+ view_loc = ui::win::DIPToScreenPoint(view_loc);
+ RECT bounds = { view_loc.x() + text_x,
+ view_loc.y() + text_y,
+ view_loc.x() + text_x + tooltip_width_,
+ view_loc.y() + line_count_ * GetTooltipHeight() };
+ SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
+
+ // Make sure the rectangle completely fits on the current monitor. If it
+ // doesn't, return false so that windows positions the tooltip at the
+ // default location.
+ gfx::Rect monitor_bounds =
+ views::GetMonitorBoundsForRect(gfx::Rect(bounds.left, bounds.right,
+ 0, 0));
+ if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
+ return false;
+ }
+
+ ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+ return true;
+}
+
+int TooltipManagerWin::CalcTooltipHeight() {
+ // Ask the tooltip for its font.
+ int height;
+ HFONT hfont = reinterpret_cast<HFONT>(
+ SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
+ if (hfont != NULL) {
+ base::win::ScopedGetDC dc(tooltip_hwnd_);
+ base::win::ScopedSelectObject font(dc, hfont);
+ ui::ScopedSetMapMode mode(dc, MM_TEXT);
+ TEXTMETRIC font_metrics;
+ GetTextMetrics(dc, &font_metrics);
+ height = font_metrics.tmHeight;
+ } else {
+ // Tooltip is using the system font. Use gfx::Font, which should pick
+ // up the system font.
+ height = gfx::Font().GetHeight();
+ }
+ // Get the margins from the tooltip
+ RECT tooltip_margin;
+ SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+ return height + tooltip_margin.top + tooltip_margin.bottom;
+}
+
+void TooltipManagerWin::UpdateTooltip(const gfx::Point& mouse_pos) {
+ View* root_view = widget_->GetRootView();
+ View* view = root_view->GetTooltipHandlerForPoint(mouse_pos);
+ if (view != last_tooltip_view_) {
+ // NOTE: This *must* be sent regardless of the visibility of the tooltip.
+ // It triggers Windows to ask for the tooltip again.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ last_tooltip_view_ = view;
+ } else if (last_tooltip_view_ != NULL) {
+ // Tooltip is showing, and mouse is over the same view. See if the tooltip
+ // text has changed.
+ gfx::Point view_point = mouse_pos;
+ View::ConvertPointToTarget(root_view, last_tooltip_view_, &view_point);
+ string16 new_tooltip_text;
+ bool has_tooltip_text =
+ last_tooltip_view_->GetTooltipText(view_point, &new_tooltip_text);
+ if (!has_tooltip_text || (new_tooltip_text != tooltip_text_)) {
+ // The text has changed, hide the popup.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ if (has_tooltip_text && !new_tooltip_text.empty() && tooltip_showing_) {
+ // New text is valid, show the popup.
+ SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+ }
+ }
+ }
+}
+
+void TooltipManagerWin::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+ gfx::Point mouse_pos_in_pixels(l_param);
+ gfx::Point mouse_pos = ui::win::ScreenToDIPPoint(mouse_pos_in_pixels);
+
+ if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
+ // NC message coordinates are in screen coordinates.
+ POINT temp = mouse_pos_in_pixels.ToPOINT();
+ ::MapWindowPoints(HWND_DESKTOP, GetParent(), &temp, 1);
+ mouse_pos_in_pixels.SetPoint(temp.x, temp.y);
+ mouse_pos = ui::win::ScreenToDIPPoint(mouse_pos_in_pixels);
+ }
+
+ if (u_msg != WM_MOUSEMOVE || last_mouse_pos_ != mouse_pos) {
+ last_mouse_pos_ = mouse_pos;
+ HideKeyboardTooltip();
+ UpdateTooltip(mouse_pos);
+ }
+ // Forward the message onto the tooltip.
+ MSG msg;
+ msg.hwnd = GetParent();
+ msg.message = u_msg;
+ msg.wParam = w_param;
+ msg.lParam = l_param;
+ SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+void TooltipManagerWin::ShowKeyboardTooltip(View* focused_view) {
+ if (tooltip_showing_) {
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ tooltip_text_.clear();
+ }
+ HideKeyboardTooltip();
+ string16 tooltip_text;
+ if (!focused_view->GetTooltipText(gfx::Point(), &tooltip_text))
+ return;
+ gfx::Rect focused_bounds = focused_view->bounds();
+ gfx::Point screen_point;
+ focused_view->ConvertPointToScreen(focused_view, &screen_point);
+ keyboard_tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ if (!keyboard_tooltip_hwnd_)
+ return;
+
+ SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+ std::numeric_limits<int16>::max());
+ int tooltip_width;
+ int line_count;
+ TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
+ screen_point.x(), screen_point.y(),
+ widget_->GetNativeView());
+ ReplaceSubstringsAfterOffset(&tooltip_text, 0, L"\n", L"\r\n");
+ TOOLINFO keyboard_toolinfo;
+ memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
+ keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
+ keyboard_toolinfo.hwnd = GetParent();
+ keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND;
+ keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str());
+ SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0,
+ reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+ SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE, TRUE,
+ reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+ if (!tooltip_height_)
+ tooltip_height_ = CalcTooltipHeight();
+ RECT rect_bounds = {screen_point.x(),
+ screen_point.y() + focused_bounds.height(),
+ screen_point.x() + tooltip_width,
+ screen_point.y() + focused_bounds.height() +
+ line_count * tooltip_height_ };
+ gfx::Rect monitor_bounds =
+ views::GetMonitorBoundsForRect(gfx::Rect(rect_bounds));
+ gfx::Rect fitted_bounds = gfx::Rect(rect_bounds);
+ fitted_bounds.AdjustToFit(monitor_bounds);
+ rect_bounds = fitted_bounds.ToRECT();
+ ::SetWindowPos(keyboard_tooltip_hwnd_, NULL, rect_bounds.left,
+ rect_bounds.top, 0, 0,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&TooltipManagerWin::DestroyKeyboardTooltipWindow,
+ keyboard_tooltip_factory_.GetWeakPtr(),
+ keyboard_tooltip_hwnd_),
+ base::TimeDelta::FromMilliseconds(kDefaultTimeout));
+}
+
+void TooltipManagerWin::HideKeyboardTooltip() {
+ if (keyboard_tooltip_hwnd_ != NULL) {
+ SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
+ keyboard_tooltip_hwnd_ = NULL;
+ }
+}
+
+void TooltipManagerWin::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
+ if (keyboard_tooltip_hwnd_ == window_to_destroy)
+ HideKeyboardTooltip();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/tooltip_manager_win.h b/chromium/ui/views/widget/tooltip_manager_win.h
new file mode 100644
index 00000000000..cfb12256a7f
--- /dev/null
+++ b/chromium/ui/views/widget/tooltip_manager_win.h
@@ -0,0 +1,153 @@
+// 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_VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
+#define UI_VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
+
+#include <windows.h>
+#include <commctrl.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+#include "ui/views/widget/tooltip_manager.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+
+class View;
+class Widget;
+
+// TooltipManager implementation for Windows.
+//
+// This class is intended to be used by NativeWidgetWin. To use this, you must
+// do the following:
+// Add the following to your MSG_MAP:
+//
+// MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+// MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+// MSG_WM_NOTIFY(OnNotify)
+//
+// With the following implementations:
+// LRESULT XXX::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param,
+// BOOL& handled) {
+// tooltip_manager_->OnMouse(u_msg, w_param, l_param);
+// handled = FALSE;
+// return 0;
+// }
+//
+// LRESULT XXX::OnNotify(int w_param, NMHDR* l_param) {
+// bool handled;
+// LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+// SetMsgHandled(handled);
+// return result;
+// }
+//
+// And of course you'll need to create the TooltipManager!
+//
+// Lastly, you'll need to override GetTooltipManager.
+//
+// See NativeWidgetWin for an example of this in action.
+class TooltipManagerWin : public TooltipManager {
+ public:
+ // Creates a TooltipManager for the specified Widget and parent window.
+ explicit TooltipManagerWin(Widget* widget);
+ virtual ~TooltipManagerWin();
+
+ // Initializes the TooltipManager returning whether initialization was
+ // successful. If this returns false the TooltipManager should be destroyed
+ // and not used.
+ bool Init();
+
+ // Notification that the view hierarchy has changed in some way.
+ virtual void UpdateTooltip() OVERRIDE;
+
+ // Invoked when the tooltip text changes for the specified views.
+ virtual void TooltipTextChanged(View* view) OVERRIDE;
+
+ // Invoked when toolbar icon gets focus.
+ virtual void ShowKeyboardTooltip(View* view) OVERRIDE;
+
+ // Invoked when toolbar loses focus.
+ virtual void HideKeyboardTooltip() OVERRIDE;
+
+ // Message handlers. These forward to the tooltip control.
+ virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+ LRESULT OnNotify(int w_param, NMHDR* l_param, bool* handled);
+
+ protected:
+ // Returns the Widget we're showing tooltips for.
+ gfx::NativeView GetParent();
+
+ // Updates the tooltip for the specified location.
+ void UpdateTooltip(const gfx::Point& location);
+
+ // Tooltip control window.
+ HWND tooltip_hwnd_;
+
+ // Tooltip information.
+ TOOLINFO toolinfo_;
+
+ // Last location of the mouse. This is in the coordinates of the rootview.
+ gfx::Point last_mouse_pos_;
+
+ // Whether or not the tooltip is showing.
+ bool tooltip_showing_;
+
+ private:
+ // Sets the tooltip position based on the x/y position of the text. If the
+ // tooltip fits, true is returned.
+ bool SetTooltipPosition(int text_x, int text_y);
+
+ // Calculates the preferred height for tooltips. This always returns a
+ // positive value.
+ int CalcTooltipHeight();
+
+ // Invoked when the timer elapses and tooltip has to be destroyed.
+ void DestroyKeyboardTooltipWindow(HWND window_to_destroy);
+
+ // Hosting Widget.
+ Widget* widget_;
+
+ // The View the mouse is under. This is null if the mouse isn't under a
+ // View.
+ View* last_tooltip_view_;
+
+ // Whether or not the view under the mouse needs to be refreshed. If this
+ // is true, when the tooltip is asked for the view under the mouse is
+ // refreshed.
+ bool last_view_out_of_sync_;
+
+ // Text for tooltip from the view.
+ string16 tooltip_text_;
+
+ // The clipped tooltip.
+ string16 clipped_text_;
+
+ // Number of lines in the tooltip.
+ int line_count_;
+
+ // Width of the last tooltip.
+ int tooltip_width_;
+
+ // control window for tooltip displayed using keyboard.
+ HWND keyboard_tooltip_hwnd_;
+
+ // Used to register DestroyTooltipWindow function with PostDelayedTask
+ // function.
+ base::WeakPtrFactory<TooltipManagerWin> keyboard_tooltip_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TooltipManagerWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
new file mode 100644
index 00000000000..e97c950261b
--- /dev/null
+++ b/chromium/ui/views/widget/widget.cc
@@ -0,0 +1,1410 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/widget.h"
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/default_theme_provider.h"
+#include "ui/base/events/event.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/l10n/l10n_font_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/focus/focus_manager_factory.h"
+#include "ui/views/focus/view_storage.h"
+#include "ui/views/focus/widget_focus_manager.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/native_widget_private.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/tooltip_manager.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_deletion_observer.h"
+#include "ui/views/widget/widget_observer.h"
+#include "ui/views/window/custom_frame_view.h"
+
+#if !defined(OS_MACOSX)
+#include "ui/views/controls/menu/menu_controller.h"
+#endif
+
+namespace views {
+
+namespace {
+
+// If |view| has a layer the layer is added to |layers|. Else this recurses
+// through the children. This is used to build a list of the layers created by
+// views that are direct children of the Widgets layer.
+void BuildRootLayers(View* view, std::vector<ui::Layer*>* layers) {
+ if (view->layer()) {
+ layers->push_back(view->layer());
+ } else {
+ for (int i = 0; i < view->child_count(); ++i)
+ BuildRootLayers(view->child_at(i), layers);
+ }
+}
+
+// Create a native widget implementation.
+// First, use the supplied one if non-NULL.
+// Finally, make a default one.
+NativeWidget* CreateNativeWidget(NativeWidget* native_widget,
+ internal::NativeWidgetDelegate* delegate) {
+ if (!native_widget) {
+ native_widget =
+ internal::NativeWidgetPrivate::CreateNativeWidget(delegate);
+ }
+ return native_widget;
+}
+
+} // namespace
+
+// A default implementation of WidgetDelegate, used by Widget when no
+// WidgetDelegate is supplied.
+class DefaultWidgetDelegate : public WidgetDelegate {
+ public:
+ DefaultWidgetDelegate(Widget* widget, const Widget::InitParams& params)
+ : widget_(widget),
+ can_activate_(!params.child &&
+ params.type != Widget::InitParams::TYPE_POPUP) {
+ }
+ virtual ~DefaultWidgetDelegate() {}
+
+ // Overridden from WidgetDelegate:
+ virtual void DeleteDelegate() OVERRIDE {
+ delete this;
+ }
+ virtual Widget* GetWidget() OVERRIDE {
+ return widget_;
+ }
+ virtual const Widget* GetWidget() const OVERRIDE {
+ return widget_;
+ }
+
+ virtual bool CanActivate() const OVERRIDE {
+ return can_activate_;
+ }
+
+ private:
+ Widget* widget_;
+ bool can_activate_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultWidgetDelegate);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, InitParams:
+
+Widget::InitParams::InitParams()
+ : type(TYPE_WINDOW),
+ delegate(NULL),
+ child(false),
+ opacity((ViewsDelegate::views_delegate &&
+ ViewsDelegate::views_delegate->UseTransparentWindows()) ?
+ TRANSLUCENT_WINDOW : INFER_OPACITY),
+ accept_events(true),
+ can_activate(true),
+ keep_on_top(false),
+ ownership(NATIVE_WIDGET_OWNS_WIDGET),
+ mirror_origin_in_rtl(false),
+ has_dropshadow(false),
+ remove_standard_frame(false),
+ use_system_default_icon(false),
+ show_state(ui::SHOW_STATE_DEFAULT),
+ double_buffer(false),
+ parent(NULL),
+ native_widget(NULL),
+ desktop_root_window_host(NULL),
+ top_level(false),
+ layer_type(ui::LAYER_TEXTURED),
+ context(NULL) {
+}
+
+Widget::InitParams::InitParams(Type type)
+ : type(type),
+ delegate(NULL),
+ child(type == TYPE_CONTROL),
+ opacity(((type == TYPE_WINDOW || type == TYPE_PANEL) &&
+ ViewsDelegate::views_delegate &&
+ ViewsDelegate::views_delegate->UseTransparentWindows()) ?
+ TRANSLUCENT_WINDOW : INFER_OPACITY),
+ accept_events(true),
+ can_activate(type != TYPE_POPUP && type != TYPE_MENU),
+ keep_on_top(type == TYPE_MENU),
+ ownership(NATIVE_WIDGET_OWNS_WIDGET),
+ mirror_origin_in_rtl(false),
+ has_dropshadow(false),
+ remove_standard_frame(false),
+ use_system_default_icon(false),
+ show_state(ui::SHOW_STATE_DEFAULT),
+ double_buffer(false),
+ parent(NULL),
+ native_widget(NULL),
+ desktop_root_window_host(NULL),
+ top_level(false),
+ layer_type(ui::LAYER_TEXTURED),
+ context(NULL) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, public:
+
+Widget::Widget()
+ : native_widget_(NULL),
+ widget_delegate_(NULL),
+ non_client_view_(NULL),
+ dragged_view_(NULL),
+ ownership_(InitParams::NATIVE_WIDGET_OWNS_WIDGET),
+ is_secondary_widget_(true),
+ frame_type_(FRAME_TYPE_DEFAULT),
+ disable_inactive_rendering_(false),
+ widget_closed_(false),
+ saved_show_state_(ui::SHOW_STATE_DEFAULT),
+ focus_on_creation_(true),
+ is_top_level_(false),
+ native_widget_initialized_(false),
+ native_widget_destroyed_(false),
+ is_mouse_button_pressed_(false),
+ is_touch_down_(false),
+ last_mouse_event_was_move_(false),
+ root_layers_dirty_(false),
+ movement_disabled_(false) {
+}
+
+Widget::~Widget() {
+ DestroyRootView();
+ if (ownership_ == InitParams::WIDGET_OWNS_NATIVE_WIDGET) {
+ delete native_widget_;
+ } else {
+ DCHECK(native_widget_destroyed_)
+ << "Destroying a widget with a live native widget. "
+ << "Widget probably should use WIDGET_OWNS_NATIVE_WIDGET ownership.";
+ }
+}
+
+// static
+Widget* Widget::CreateWindow(WidgetDelegate* delegate) {
+ return CreateWindowWithBounds(delegate, gfx::Rect());
+}
+
+// static
+Widget* Widget::CreateWindowWithBounds(WidgetDelegate* delegate,
+ const gfx::Rect& bounds) {
+ Widget* widget = new Widget;
+ Widget::InitParams params;
+ params.bounds = bounds;
+ params.delegate = delegate;
+ params.top_level = true;
+ widget->Init(params);
+ return widget;
+}
+
+// static
+Widget* Widget::CreateWindowWithParent(WidgetDelegate* delegate,
+ gfx::NativeWindow parent) {
+ return CreateWindowWithParentAndBounds(delegate, parent, gfx::Rect());
+}
+
+// static
+Widget* Widget::CreateWindowWithParentAndBounds(WidgetDelegate* delegate,
+ gfx::NativeWindow parent,
+ const gfx::Rect& bounds) {
+ Widget* widget = new Widget;
+ Widget::InitParams params;
+ params.delegate = delegate;
+ params.parent = parent;
+ params.bounds = bounds;
+ widget->Init(params);
+ return widget;
+}
+
+// static
+Widget* Widget::CreateWindowWithContext(WidgetDelegate* delegate,
+ gfx::NativeView context) {
+ return CreateWindowWithContextAndBounds(delegate, context, gfx::Rect());
+}
+
+// static
+Widget* Widget::CreateWindowWithContextAndBounds(WidgetDelegate* delegate,
+ gfx::NativeView context,
+ const gfx::Rect& bounds) {
+ Widget* widget = new Widget;
+ Widget::InitParams params;
+ params.delegate = delegate;
+ params.context = context;
+ params.bounds = bounds;
+ widget->Init(params);
+ return widget;
+}
+
+// static
+Widget* Widget::GetWidgetForNativeView(gfx::NativeView native_view) {
+ internal::NativeWidgetPrivate* native_widget =
+ internal::NativeWidgetPrivate::GetNativeWidgetForNativeView(native_view);
+ return native_widget ? native_widget->GetWidget() : NULL;
+}
+
+// static
+Widget* Widget::GetWidgetForNativeWindow(gfx::NativeWindow native_window) {
+ internal::NativeWidgetPrivate* native_widget =
+ internal::NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
+ native_window);
+ return native_widget ? native_widget->GetWidget() : NULL;
+}
+
+// static
+Widget* Widget::GetTopLevelWidgetForNativeView(gfx::NativeView native_view) {
+ internal::NativeWidgetPrivate* native_widget =
+ internal::NativeWidgetPrivate::GetTopLevelNativeWidget(native_view);
+ return native_widget ? native_widget->GetWidget() : NULL;
+}
+
+
+// static
+void Widget::GetAllChildWidgets(gfx::NativeView native_view,
+ Widgets* children) {
+ internal::NativeWidgetPrivate::GetAllChildWidgets(native_view, children);
+}
+
+// static
+void Widget::ReparentNativeView(gfx::NativeView native_view,
+ gfx::NativeView new_parent) {
+ internal::NativeWidgetPrivate::ReparentNativeView(native_view, new_parent);
+}
+
+// static
+int Widget::GetLocalizedContentsWidth(int col_resource_id) {
+ return ui::GetLocalizedContentsWidthForFont(col_resource_id,
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont));
+}
+
+// static
+int Widget::GetLocalizedContentsHeight(int row_resource_id) {
+ return ui::GetLocalizedContentsHeightForFont(row_resource_id,
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont));
+}
+
+// static
+gfx::Size Widget::GetLocalizedContentsSize(int col_resource_id,
+ int row_resource_id) {
+ return gfx::Size(GetLocalizedContentsWidth(col_resource_id),
+ GetLocalizedContentsHeight(row_resource_id));
+}
+
+// static
+bool Widget::RequiresNonClientView(InitParams::Type type) {
+ return type == InitParams::TYPE_WINDOW ||
+ type == InitParams::TYPE_PANEL ||
+ type == InitParams::TYPE_BUBBLE;
+}
+
+void Widget::Init(const InitParams& in_params) {
+ TRACE_EVENT0("views", "Widget::Init");
+ InitParams params = in_params;
+
+ is_top_level_ = params.top_level ||
+ (!params.child &&
+ params.type != InitParams::TYPE_CONTROL &&
+ params.type != InitParams::TYPE_TOOLTIP);
+ params.top_level = is_top_level_;
+ if (params.opacity == InitParams::INFER_OPACITY) {
+#if defined(OS_WIN) && defined(USE_AURA)
+ // By default, make all top-level windows but the main window transparent
+ // initially so that they can be made to fade in.
+ if (is_top_level_ && params.type != InitParams::TYPE_WINDOW)
+ params.opacity = InitParams::TRANSLUCENT_WINDOW;
+ else
+ params.opacity = InitParams::OPAQUE_WINDOW;
+#else
+ params.opacity = InitParams::OPAQUE_WINDOW;
+#endif
+ }
+
+ if (ViewsDelegate::views_delegate)
+ ViewsDelegate::views_delegate->OnBeforeWidgetInit(&params, this);
+
+ widget_delegate_ = params.delegate ?
+ params.delegate : new DefaultWidgetDelegate(this, params);
+ ownership_ = params.ownership;
+ native_widget_ = CreateNativeWidget(params.native_widget, this)->
+ AsNativeWidgetPrivate();
+ root_view_.reset(CreateRootView());
+ default_theme_provider_.reset(new ui::DefaultThemeProvider);
+ if (params.type == InitParams::TYPE_MENU) {
+ is_mouse_button_pressed_ =
+ internal::NativeWidgetPrivate::IsMouseButtonDown();
+ }
+ native_widget_->InitNativeWidget(params);
+ if (RequiresNonClientView(params.type)) {
+ non_client_view_ = new NonClientView;
+ non_client_view_->SetFrameView(CreateNonClientFrameView());
+ // Create the ClientView, add it to the NonClientView and add the
+ // NonClientView to the RootView. This will cause everything to be parented.
+ non_client_view_->set_client_view(widget_delegate_->CreateClientView(this));
+ non_client_view_->SetOverlayView(widget_delegate_->CreateOverlayView());
+ SetContentsView(non_client_view_);
+ // Initialize the window's title before setting the window's initial bounds;
+ // the frame view's preferred height may depend on the presence of a title.
+ UpdateWindowTitle();
+ SetInitialBounds(params.bounds);
+ if (params.show_state == ui::SHOW_STATE_MAXIMIZED)
+ Maximize();
+ else if (params.show_state == ui::SHOW_STATE_MINIMIZED)
+ Minimize();
+ } else if (params.delegate) {
+ SetContentsView(params.delegate->GetContentsView());
+ SetInitialBoundsForFramelessWindow(params.bounds);
+ }
+ native_widget_initialized_ = true;
+}
+
+// Unconverted methods (see header) --------------------------------------------
+
+gfx::NativeView Widget::GetNativeView() const {
+ return native_widget_->GetNativeView();
+}
+
+gfx::NativeWindow Widget::GetNativeWindow() const {
+ return native_widget_->GetNativeWindow();
+}
+
+void Widget::AddObserver(WidgetObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void Widget::RemoveObserver(WidgetObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool Widget::HasObserver(WidgetObserver* observer) {
+ return observers_.HasObserver(observer);
+}
+
+bool Widget::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
+ return false;
+}
+
+void Widget::ViewHierarchyChanged(
+ const View::ViewHierarchyChangedDetails& details) {
+ if (!details.is_add) {
+ if (details.child == dragged_view_)
+ dragged_view_ = NULL;
+ FocusManager* focus_manager = GetFocusManager();
+ if (focus_manager)
+ focus_manager->ViewRemoved(details.child);
+ ViewStorage::GetInstance()->ViewRemoved(details.child);
+ native_widget_->ViewRemoved(details.child);
+ }
+}
+
+void Widget::NotifyNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view) {
+ if (!attached) {
+ FocusManager* focus_manager = GetFocusManager();
+ // We are being removed from a window hierarchy. Treat this as
+ // the root_view_ being removed.
+ if (focus_manager)
+ focus_manager->ViewRemoved(root_view_.get());
+ }
+ root_view_->NotifyNativeViewHierarchyChanged(attached, native_view);
+}
+
+// Converted methods (see header) ----------------------------------------------
+
+Widget* Widget::GetTopLevelWidget() {
+ return const_cast<Widget*>(
+ static_cast<const Widget*>(this)->GetTopLevelWidget());
+}
+
+const Widget* Widget::GetTopLevelWidget() const {
+ // GetTopLevelNativeWidget doesn't work during destruction because
+ // property is gone after gobject gets deleted. Short circuit here
+ // for toplevel so that InputMethod can remove itself from
+ // focus manager.
+ return is_top_level() ? this : native_widget_->GetTopLevelWidget();
+}
+
+void Widget::SetContentsView(View* view) {
+ // Do not SetContentsView() again if it is already set to the same view.
+ if (view == GetContentsView())
+ return;
+ root_view_->SetContentsView(view);
+ if (non_client_view_ != view) {
+ // |non_client_view_| can only be non-NULL here if RequiresNonClientView()
+ // was true when the widget was initialized. Creating widgets with non
+ // client views and then setting the contents view can cause subtle
+ // problems on Windows, where the native widget thinks there is still a
+ // |non_client_view_|. If you get this error, either use a different type
+ // when initializing the widget, or don't call SetContentsView().
+ DCHECK(!non_client_view_);
+ non_client_view_ = NULL;
+ }
+}
+
+View* Widget::GetContentsView() {
+ return root_view_->GetContentsView();
+}
+
+gfx::Rect Widget::GetWindowBoundsInScreen() const {
+ return native_widget_->GetWindowBoundsInScreen();
+}
+
+gfx::Rect Widget::GetClientAreaBoundsInScreen() const {
+ return native_widget_->GetClientAreaBoundsInScreen();
+}
+
+gfx::Rect Widget::GetRestoredBounds() const {
+ return native_widget_->GetRestoredBounds();
+}
+
+void Widget::SetBounds(const gfx::Rect& bounds) {
+ native_widget_->SetBounds(bounds);
+}
+
+void Widget::SetSize(const gfx::Size& size) {
+ native_widget_->SetSize(size);
+}
+
+void Widget::CenterWindow(const gfx::Size& size) {
+ native_widget_->CenterWindow(size);
+}
+
+void Widget::SetBoundsConstrained(const gfx::Rect& bounds) {
+ gfx::Rect work_area =
+ gfx::Screen::GetScreenFor(GetNativeView())->GetDisplayNearestPoint(
+ bounds.origin()).work_area();
+ if (work_area.IsEmpty()) {
+ SetBounds(bounds);
+ } else {
+ // Inset the work area slightly.
+ work_area.Inset(10, 10, 10, 10);
+ work_area.AdjustToFit(bounds);
+ SetBounds(work_area);
+ }
+}
+
+void Widget::SetVisibilityChangedAnimationsEnabled(bool value) {
+ native_widget_->SetVisibilityChangedAnimationsEnabled(value);
+}
+
+Widget::MoveLoopResult Widget::RunMoveLoop(const gfx::Vector2d& drag_offset,
+ MoveLoopSource source) {
+ return native_widget_->RunMoveLoop(drag_offset, source);
+}
+
+void Widget::EndMoveLoop() {
+ native_widget_->EndMoveLoop();
+}
+
+void Widget::StackAboveWidget(Widget* widget) {
+ native_widget_->StackAbove(widget->GetNativeView());
+}
+
+void Widget::StackAbove(gfx::NativeView native_view) {
+ native_widget_->StackAbove(native_view);
+}
+
+void Widget::StackAtTop() {
+ native_widget_->StackAtTop();
+}
+
+void Widget::StackBelow(gfx::NativeView native_view) {
+ native_widget_->StackBelow(native_view);
+}
+
+void Widget::SetShape(gfx::NativeRegion shape) {
+ native_widget_->SetShape(shape);
+}
+
+void Widget::Close() {
+ if (widget_closed_) {
+ // It appears we can hit this code path if you close a modal dialog then
+ // close the last browser before the destructor is hit, which triggers
+ // invoking Close again.
+ return;
+ }
+
+ bool can_close = true;
+ if (non_client_view_)
+ can_close = non_client_view_->CanClose();
+ if (can_close) {
+ SaveWindowPlacement();
+
+ // During tear-down the top-level focus manager becomes unavailable to
+ // GTK tabbed panes and their children, so normal deregistration via
+ // |FormManager::ViewRemoved()| calls are fouled. We clear focus here
+ // to avoid these redundant steps and to avoid accessing deleted views
+ // that may have been in focus.
+ if (is_top_level() && focus_manager_.get())
+ focus_manager_->SetFocusedView(NULL);
+
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetClosing(this));
+ native_widget_->Close();
+ widget_closed_ = true;
+ }
+}
+
+void Widget::CloseNow() {
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetClosing(this));
+ native_widget_->CloseNow();
+}
+
+bool Widget::IsClosed() const {
+ return widget_closed_;
+}
+
+void Widget::Show() {
+ TRACE_EVENT0("views", "Widget::Show");
+ if (non_client_view_) {
+#if defined(OS_MACOSX)
+ // On the Mac the FullScreenBookmarkBar test is different then for any other
+ // OS. Since the new maximize logic from ash does not apply to the mac, we
+ // continue to ignore the fullscreen mode here.
+ if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED &&
+ !initial_restored_bounds_.IsEmpty()) {
+ native_widget_->ShowMaximizedWithBounds(initial_restored_bounds_);
+ } else {
+ native_widget_->ShowWithWindowState(saved_show_state_);
+ }
+#else
+ // While initializing, the kiosk mode will go to full screen before the
+ // widget gets shown. In that case we stay in full screen mode, regardless
+ // of the |saved_show_state_| member.
+ if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED &&
+ !initial_restored_bounds_.IsEmpty() &&
+ !IsFullscreen()) {
+ native_widget_->ShowMaximizedWithBounds(initial_restored_bounds_);
+ } else {
+ native_widget_->ShowWithWindowState(
+ IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : saved_show_state_);
+ }
+#endif
+ // |saved_show_state_| only applies the first time the window is shown.
+ // If we don't reset the value the window may be shown maximized every time
+ // it is subsequently shown after being hidden.
+ saved_show_state_ = ui::SHOW_STATE_NORMAL;
+ } else {
+ native_widget_->Show();
+ }
+}
+
+void Widget::Hide() {
+ native_widget_->Hide();
+}
+
+void Widget::ShowInactive() {
+ // If this gets called with saved_show_state_ == ui::SHOW_STATE_MAXIMIZED,
+ // call SetBounds()with the restored bounds to set the correct size. This
+ // normally should not happen, but if it does we should avoid showing unsized
+ // windows.
+ if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED &&
+ !initial_restored_bounds_.IsEmpty()) {
+ SetBounds(initial_restored_bounds_);
+ saved_show_state_ = ui::SHOW_STATE_NORMAL;
+ }
+ native_widget_->ShowWithWindowState(ui::SHOW_STATE_INACTIVE);
+}
+
+void Widget::Activate() {
+ native_widget_->Activate();
+}
+
+void Widget::Deactivate() {
+ native_widget_->Deactivate();
+}
+
+bool Widget::IsActive() const {
+ return native_widget_->IsActive();
+}
+
+void Widget::DisableInactiveRendering() {
+ SetInactiveRenderingDisabled(true);
+}
+
+void Widget::SetAlwaysOnTop(bool on_top) {
+ native_widget_->SetAlwaysOnTop(on_top);
+}
+
+void Widget::Maximize() {
+ native_widget_->Maximize();
+}
+
+void Widget::Minimize() {
+ native_widget_->Minimize();
+}
+
+void Widget::Restore() {
+ native_widget_->Restore();
+}
+
+bool Widget::IsMaximized() const {
+ return native_widget_->IsMaximized();
+}
+
+bool Widget::IsMinimized() const {
+ return native_widget_->IsMinimized();
+}
+
+void Widget::SetFullscreen(bool fullscreen) {
+ native_widget_->SetFullscreen(fullscreen);
+}
+
+bool Widget::IsFullscreen() const {
+ return native_widget_->IsFullscreen();
+}
+
+void Widget::SetOpacity(unsigned char opacity) {
+ native_widget_->SetOpacity(opacity);
+}
+
+void Widget::SetUseDragFrame(bool use_drag_frame) {
+ native_widget_->SetUseDragFrame(use_drag_frame);
+}
+
+void Widget::FlashFrame(bool flash) {
+ native_widget_->FlashFrame(flash);
+}
+
+View* Widget::GetRootView() {
+ return root_view_.get();
+}
+
+const View* Widget::GetRootView() const {
+ return root_view_.get();
+}
+
+bool Widget::IsVisible() const {
+ return native_widget_->IsVisible();
+}
+
+ui::ThemeProvider* Widget::GetThemeProvider() const {
+ const Widget* root_widget = GetTopLevelWidget();
+ if (root_widget && root_widget != this) {
+ // Attempt to get the theme provider, and fall back to the default theme
+ // provider if not found.
+ ui::ThemeProvider* provider = root_widget->GetThemeProvider();
+ if (provider)
+ return provider;
+
+ provider = root_widget->default_theme_provider_.get();
+ if (provider)
+ return provider;
+ }
+ return default_theme_provider_.get();
+}
+
+const ui::NativeTheme* Widget::GetNativeTheme() const {
+ return native_widget_->GetNativeTheme();
+}
+
+FocusManager* Widget::GetFocusManager() {
+ Widget* toplevel_widget = GetTopLevelWidget();
+ return toplevel_widget ? toplevel_widget->focus_manager_.get() : NULL;
+}
+
+const FocusManager* Widget::GetFocusManager() const {
+ const Widget* toplevel_widget = GetTopLevelWidget();
+ return toplevel_widget ? toplevel_widget->focus_manager_.get() : NULL;
+}
+
+InputMethod* Widget::GetInputMethod() {
+ return const_cast<InputMethod*>(
+ const_cast<const Widget*>(this)->GetInputMethod());
+}
+
+const InputMethod* Widget::GetInputMethod() const {
+ if (is_top_level()) {
+ if (!input_method_.get())
+ input_method_ = const_cast<Widget*>(this)->CreateInputMethod().Pass();
+ return input_method_.get();
+ } else {
+ const Widget* toplevel = GetTopLevelWidget();
+ // If GetTopLevelWidget() returns itself which is not toplevel,
+ // the widget is detached from toplevel widget.
+ // TODO(oshima): Fix GetTopLevelWidget() to return NULL
+ // if there is no toplevel. We probably need to add GetTopMostWidget()
+ // to replace some use cases.
+ return (toplevel && toplevel != this) ? toplevel->GetInputMethod() : NULL;
+ }
+}
+
+void Widget::RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ dragged_view_ = view;
+ native_widget_->RunShellDrag(view, data, location, operation, source);
+ // If the view is removed during the drag operation, dragged_view_ is set to
+ // NULL.
+ if (view && dragged_view_ == view) {
+ dragged_view_ = NULL;
+ view->OnDragDone();
+ }
+}
+
+void Widget::SchedulePaintInRect(const gfx::Rect& rect) {
+ native_widget_->SchedulePaintInRect(rect);
+}
+
+void Widget::SetCursor(gfx::NativeCursor cursor) {
+ native_widget_->SetCursor(cursor);
+}
+
+bool Widget::IsMouseEventsEnabled() const {
+ return native_widget_->IsMouseEventsEnabled();
+}
+
+void Widget::SetNativeWindowProperty(const char* name, void* value) {
+ native_widget_->SetNativeWindowProperty(name, value);
+}
+
+void* Widget::GetNativeWindowProperty(const char* name) const {
+ return native_widget_->GetNativeWindowProperty(name);
+}
+
+void Widget::UpdateWindowTitle() {
+ if (!non_client_view_)
+ return;
+
+ // Update the native frame's text. We do this regardless of whether or not
+ // the native frame is being used, since this also updates the taskbar, etc.
+ string16 window_title = widget_delegate_->GetWindowTitle();
+ base::i18n::AdjustStringForLocaleDirection(&window_title);
+ native_widget_->SetWindowTitle(window_title);
+ non_client_view_->UpdateWindowTitle();
+
+ // If the non-client view is rendering its own title, it'll need to relayout
+ // now and to get a paint update later on.
+ non_client_view_->Layout();
+}
+
+void Widget::UpdateWindowIcon() {
+ if (non_client_view_)
+ non_client_view_->UpdateWindowIcon();
+ native_widget_->SetWindowIcons(widget_delegate_->GetWindowIcon(),
+ widget_delegate_->GetWindowAppIcon());
+}
+
+FocusTraversable* Widget::GetFocusTraversable() {
+ return static_cast<internal::RootView*>(root_view_.get());
+}
+
+void Widget::ThemeChanged() {
+ root_view_->ThemeChanged();
+}
+
+void Widget::LocaleChanged() {
+ root_view_->LocaleChanged();
+}
+
+void Widget::SetFocusTraversableParent(FocusTraversable* parent) {
+ root_view_->SetFocusTraversableParent(parent);
+}
+
+void Widget::SetFocusTraversableParentView(View* parent_view) {
+ root_view_->SetFocusTraversableParentView(parent_view);
+}
+
+void Widget::ClearNativeFocus() {
+ native_widget_->ClearNativeFocus();
+}
+
+NonClientFrameView* Widget::CreateNonClientFrameView() {
+ NonClientFrameView* frame_view =
+ widget_delegate_->CreateNonClientFrameView(this);
+ if (!frame_view)
+ frame_view = native_widget_->CreateNonClientFrameView();
+ if (!frame_view && ViewsDelegate::views_delegate) {
+ frame_view =
+ ViewsDelegate::views_delegate->CreateDefaultNonClientFrameView(this);
+ }
+ if (frame_view)
+ return frame_view;
+
+ CustomFrameView* custom_frame_view = new CustomFrameView;
+ custom_frame_view->Init(this);
+ return custom_frame_view;
+}
+
+bool Widget::ShouldUseNativeFrame() const {
+ if (frame_type_ != FRAME_TYPE_DEFAULT)
+ return frame_type_ == FRAME_TYPE_FORCE_NATIVE;
+ return native_widget_->ShouldUseNativeFrame();
+}
+
+void Widget::DebugToggleFrameType() {
+ if (frame_type_ == FRAME_TYPE_DEFAULT) {
+ frame_type_ = ShouldUseNativeFrame() ? FRAME_TYPE_FORCE_CUSTOM :
+ FRAME_TYPE_FORCE_NATIVE;
+ } else {
+ frame_type_ = frame_type_ == FRAME_TYPE_FORCE_CUSTOM ?
+ FRAME_TYPE_FORCE_NATIVE : FRAME_TYPE_FORCE_CUSTOM;
+ }
+ FrameTypeChanged();
+}
+
+void Widget::FrameTypeChanged() {
+ native_widget_->FrameTypeChanged();
+}
+
+const ui::Compositor* Widget::GetCompositor() const {
+ return native_widget_->GetCompositor();
+}
+
+ui::Compositor* Widget::GetCompositor() {
+ return native_widget_->GetCompositor();
+}
+
+ui::Layer* Widget::GetLayer() {
+ return native_widget_->GetLayer();
+}
+
+void Widget::ReorderNativeViews() {
+ native_widget_->ReorderNativeViews();
+}
+
+void Widget::UpdateRootLayers() {
+ // Calculate the layers requires traversing the tree, and since nearly any
+ // mutation of the tree can trigger this call we delay until absolutely
+ // necessary.
+ root_layers_dirty_ = true;
+}
+
+const NativeWidget* Widget::native_widget() const {
+ return native_widget_;
+}
+
+NativeWidget* Widget::native_widget() {
+ return native_widget_;
+}
+
+void Widget::SetCapture(View* view) {
+ if (internal::NativeWidgetPrivate::IsMouseButtonDown())
+ is_mouse_button_pressed_ = true;
+ if (internal::NativeWidgetPrivate::IsTouchDown())
+ is_touch_down_ = true;
+ root_view_->SetMouseHandler(view);
+ if (!native_widget_->HasCapture())
+ native_widget_->SetCapture();
+}
+
+void Widget::ReleaseCapture() {
+ if (native_widget_->HasCapture())
+ native_widget_->ReleaseCapture();
+}
+
+bool Widget::HasCapture() {
+ return native_widget_->HasCapture();
+}
+
+void Widget::TooltipTextChanged(View* view) {
+ TooltipManager* manager = native_widget_private()->GetTooltipManager();
+ if (manager)
+ manager->TooltipTextChanged(view);
+}
+
+bool Widget::SetInitialFocus() {
+ View* v = widget_delegate_->GetInitiallyFocusedView();
+ if (!focus_on_creation_) {
+ // If not focusing the window now, tell the focus manager which view to
+ // focus when the window is restored.
+ if (v)
+ focus_manager_->SetStoredFocusView(v);
+ return true;
+ }
+ if (v)
+ v->RequestFocus();
+ return !!v;
+}
+
+View* Widget::GetChildViewParent() {
+ return GetContentsView() ? GetContentsView() : GetRootView();
+}
+
+gfx::Rect Widget::GetWorkAreaBoundsInScreen() const {
+ return native_widget_->GetWorkAreaBoundsInScreen();
+}
+
+void Widget::SynthesizeMouseMoveEvent() {
+ last_mouse_event_was_move_ = false;
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED,
+ last_mouse_event_position_,
+ last_mouse_event_position_,
+ ui::EF_IS_SYNTHESIZED);
+ root_view_->OnMouseMoved(mouse_event);
+}
+
+void Widget::OnOwnerClosing() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, NativeWidgetDelegate implementation:
+
+bool Widget::IsModal() const {
+ return widget_delegate_->GetModalType() != ui::MODAL_TYPE_NONE;
+}
+
+bool Widget::IsDialogBox() const {
+ return !!widget_delegate_->AsDialogDelegate();
+}
+
+bool Widget::CanActivate() const {
+ return widget_delegate_->CanActivate();
+}
+
+bool Widget::IsInactiveRenderingDisabled() const {
+ return disable_inactive_rendering_;
+}
+
+void Widget::EnableInactiveRendering() {
+ SetInactiveRenderingDisabled(false);
+}
+
+void Widget::OnNativeWidgetActivationChanged(bool active) {
+ // On windows we may end up here before we've completed initialization (from
+ // an WM_NCACTIVATE). If that happens the WidgetDelegate likely doesn't know
+ // the Widget and will crash attempting to access it.
+ if (!active && native_widget_initialized_)
+ SaveWindowPlacement();
+
+ FOR_EACH_OBSERVER(WidgetObserver, observers_,
+ OnWidgetActivationChanged(this, active));
+}
+
+void Widget::OnNativeFocus(gfx::NativeView old_focused_view) {
+ WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(old_focused_view,
+ GetNativeView());
+}
+
+void Widget::OnNativeBlur(gfx::NativeView new_focused_view) {
+ WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(GetNativeView(),
+ new_focused_view);
+}
+
+void Widget::OnNativeWidgetVisibilityChanged(bool visible) {
+ View* root = GetRootView();
+ if (root)
+ root->PropagateVisibilityNotifications(root, visible);
+ FOR_EACH_OBSERVER(WidgetObserver, observers_,
+ OnWidgetVisibilityChanged(this, visible));
+ if (GetCompositor() && root && root->layer())
+ root->layer()->SetVisible(visible);
+}
+
+void Widget::OnNativeWidgetCreated(bool desktop_widget) {
+ if (is_top_level())
+ focus_manager_.reset(FocusManagerFactory::Create(this, desktop_widget));
+
+ native_widget_->InitModalType(widget_delegate_->GetModalType());
+
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetCreated(this));
+}
+
+void Widget::OnNativeWidgetDestroying() {
+ // Tell the focus manager (if any) that root_view is being removed
+ // in case that the focused view is under this root view.
+ if (GetFocusManager())
+ GetFocusManager()->ViewRemoved(root_view_.get());
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetDestroying(this));
+ if (non_client_view_)
+ non_client_view_->WindowClosing();
+ widget_delegate_->WindowClosing();
+}
+
+void Widget::OnNativeWidgetDestroyed() {
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetDestroyed(this));
+ widget_delegate_->DeleteDelegate();
+ widget_delegate_ = NULL;
+ native_widget_destroyed_ = true;
+}
+
+gfx::Size Widget::GetMinimumSize() {
+ return non_client_view_ ? non_client_view_->GetMinimumSize() : gfx::Size();
+}
+
+gfx::Size Widget::GetMaximumSize() {
+ return non_client_view_ ? non_client_view_->GetMaximumSize() : gfx::Size();
+}
+
+void Widget::OnNativeWidgetMove() {
+ widget_delegate_->OnWidgetMove();
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetBoundsChanged(
+ this,
+ GetWindowBoundsInScreen()));
+}
+
+void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) {
+ root_view_->SetSize(new_size);
+
+ // Size changed notifications can fire prior to full initialization
+ // i.e. during session restore. Avoid saving session state during these
+ // startup procedures.
+ if (native_widget_initialized_)
+ SaveWindowPlacement();
+
+ FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetBoundsChanged(
+ this,
+ GetWindowBoundsInScreen()));
+}
+
+void Widget::OnNativeWidgetBeginUserBoundsChange() {
+ widget_delegate_->OnWindowBeginUserBoundsChange();
+}
+
+void Widget::OnNativeWidgetEndUserBoundsChange() {
+ widget_delegate_->OnWindowEndUserBoundsChange();
+}
+
+bool Widget::HasFocusManager() const {
+ return !!focus_manager_.get();
+}
+
+bool Widget::OnNativeWidgetPaintAccelerated(const gfx::Rect& dirty_region) {
+ ui::Compositor* compositor = GetCompositor();
+ if (!compositor)
+ return false;
+
+ compositor->ScheduleRedrawRect(dirty_region);
+ return true;
+}
+
+void Widget::OnNativeWidgetPaint(gfx::Canvas* canvas) {
+ // On Linux Aura, we can get here during Init() because of the
+ // SetInitialBounds call.
+ if (native_widget_initialized_)
+ GetRootView()->Paint(canvas);
+}
+
+int Widget::GetNonClientComponent(const gfx::Point& point) {
+ int component = non_client_view_ ?
+ non_client_view_->NonClientHitTest(point) :
+ HTNOWHERE;
+
+ if (movement_disabled_ && (component == HTCAPTION || component == HTSYSMENU))
+ return HTNOWHERE;
+
+ return component;
+}
+
+void Widget::OnKeyEvent(ui::KeyEvent* event) {
+ static_cast<internal::RootView*>(GetRootView())->
+ DispatchKeyEvent(event);
+}
+
+void Widget::OnMouseEvent(ui::MouseEvent* event) {
+ if (!IsMouseEventsEnabled())
+ return;
+
+ View* root_view = GetRootView();
+ switch (event->type()) {
+ case ui::ET_MOUSE_PRESSED: {
+ last_mouse_event_was_move_ = false;
+
+ // We may get deleted by the time we return from OnMousePressed. So we
+ // use an observer to make sure we are still alive.
+ WidgetDeletionObserver widget_deletion_observer(this);
+
+ // Make sure we're still visible before we attempt capture as the mouse
+ // press processing may have made the window hide (as happens with menus).
+
+ // It is possible for a View to show a context menu on mouse-press. Since
+ // the menu does a capture and starts a nested message-loop, the release
+ // would go to the menu. The next click (i.e. both mouse-press and release
+ // events) also go to the menu. The menu (and the nested message-loop)
+ // gets closed after this second release event. The code then resumes from
+ // here. So make sure that the mouse-button is still down before doing a
+ // capture.
+ if (root_view && root_view->OnMousePressed(*event) &&
+ widget_deletion_observer.IsWidgetAlive() && IsVisible() &&
+ internal::NativeWidgetPrivate::IsMouseButtonDown()) {
+ is_mouse_button_pressed_ = true;
+ if (!native_widget_->HasCapture())
+ native_widget_->SetCapture();
+ event->SetHandled();
+ }
+ return;
+ }
+ case ui::ET_MOUSE_RELEASED:
+ last_mouse_event_was_move_ = false;
+ is_mouse_button_pressed_ = false;
+ // Release capture first, to avoid confusion if OnMouseReleased blocks.
+ if (native_widget_->HasCapture() &&
+ ShouldReleaseCaptureOnMouseReleased()) {
+ native_widget_->ReleaseCapture();
+ }
+ if (root_view)
+ root_view->OnMouseReleased(*event);
+ if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0)
+ event->SetHandled();
+ return;
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ if (native_widget_->HasCapture() && is_mouse_button_pressed_) {
+ last_mouse_event_was_move_ = false;
+ if (root_view)
+ root_view->OnMouseDragged(*event);
+ } else if (!last_mouse_event_was_move_ ||
+ last_mouse_event_position_ != event->location()) {
+ last_mouse_event_position_ = event->location();
+ last_mouse_event_was_move_ = true;
+ if (root_view)
+ root_view->OnMouseMoved(*event);
+ }
+ return;
+ case ui::ET_MOUSE_EXITED:
+ last_mouse_event_was_move_ = false;
+ if (root_view)
+ root_view->OnMouseExited(*event);
+ return;
+ case ui::ET_MOUSEWHEEL:
+ if (root_view && root_view->OnMouseWheel(
+ static_cast<const ui::MouseWheelEvent&>(*event)))
+ event->SetHandled();
+ return;
+ default:
+ return;
+ }
+ event->SetHandled();
+}
+
+void Widget::OnMouseCaptureLost() {
+ if (is_mouse_button_pressed_ || is_touch_down_) {
+ View* root_view = GetRootView();
+ if (root_view)
+ root_view->OnMouseCaptureLost();
+ }
+ is_touch_down_ = false;
+ is_mouse_button_pressed_ = false;
+}
+
+void Widget::OnTouchEvent(ui::TouchEvent* event) {
+ static_cast<internal::RootView*>(GetRootView())->
+ DispatchTouchEvent(event);
+}
+
+void Widget::OnScrollEvent(ui::ScrollEvent* event) {
+ static_cast<internal::RootView*>(GetRootView())->
+ DispatchScrollEvent(event);
+}
+
+void Widget::OnGestureEvent(ui::GestureEvent* event) {
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP_DOWN:
+ is_touch_down_ = true;
+ // We explicitly don't capture here. Not capturing enables multiple
+ // widgets to get tap events at the same time. Views (such as tab
+ // dragging) may explicitly capture.
+ break;
+
+ case ui::ET_GESTURE_END:
+ if (event->details().touch_points() == 1) {
+ is_touch_down_ = false;
+ if (ShouldReleaseCaptureOnMouseReleased())
+ ReleaseCapture();
+ }
+ break;
+
+ default:
+ break;
+ }
+ static_cast<internal::RootView*>(GetRootView())->DispatchGestureEvent(event);
+}
+
+bool Widget::ExecuteCommand(int command_id) {
+ return widget_delegate_->ExecuteWindowsCommand(command_id);
+}
+
+InputMethod* Widget::GetInputMethodDirect() {
+ return input_method_.get();
+}
+
+const std::vector<ui::Layer*>& Widget::GetRootLayers() {
+ if (root_layers_dirty_) {
+ root_layers_dirty_ = false;
+ root_layers_.clear();
+ BuildRootLayers(GetRootView(), &root_layers_);
+ }
+ return root_layers_;
+}
+
+bool Widget::HasHitTestMask() const {
+ return widget_delegate_->WidgetHasHitTestMask();
+}
+
+void Widget::GetHitTestMask(gfx::Path* mask) const {
+ DCHECK(mask);
+ widget_delegate_->GetWidgetHitTestMask(mask);
+}
+
+Widget* Widget::AsWidget() {
+ return this;
+}
+
+const Widget* Widget::AsWidget() const {
+ return this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, FocusTraversable implementation:
+
+FocusSearch* Widget::GetFocusSearch() {
+ return root_view_->GetFocusSearch();
+}
+
+FocusTraversable* Widget::GetFocusTraversableParent() {
+ // We are a proxy to the root view, so we should be bypassed when traversing
+ // up and as a result this should not be called.
+ NOTREACHED();
+ return NULL;
+}
+
+View* Widget::GetFocusTraversableParentView() {
+ // We are a proxy to the root view, so we should be bypassed when traversing
+ // up and as a result this should not be called.
+ NOTREACHED();
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, protected:
+
+internal::RootView* Widget::CreateRootView() {
+ return new internal::RootView(this);
+}
+
+void Widget::DestroyRootView() {
+ non_client_view_ = NULL;
+ root_view_.reset();
+ // Input method has to be destroyed before focus manager.
+ input_method_.reset();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, private:
+
+bool Widget::ShouldReleaseCaptureOnMouseReleased() const {
+ return true;
+}
+
+void Widget::SetInactiveRenderingDisabled(bool value) {
+ if (value == disable_inactive_rendering_)
+ return;
+
+ disable_inactive_rendering_ = value;
+ if (non_client_view_)
+ non_client_view_->SetInactiveRenderingDisabled(value);
+ native_widget_->SetInactiveRenderingDisabled(value);
+}
+
+void Widget::SaveWindowPlacement() {
+ // The window delegate does the actual saving for us. It seems like (judging
+ // by go/crash) that in some circumstances we can end up here after
+ // WM_DESTROY, at which point the window delegate is likely gone. So just
+ // bail.
+ if (!widget_delegate_)
+ return;
+
+ ui::WindowShowState show_state = ui::SHOW_STATE_NORMAL;
+ gfx::Rect bounds;
+ native_widget_->GetWindowPlacement(&bounds, &show_state);
+ widget_delegate_->SaveWindowPlacement(bounds, show_state);
+}
+
+void Widget::SetInitialBounds(const gfx::Rect& bounds) {
+ if (!non_client_view_)
+ return;
+
+ gfx::Rect saved_bounds;
+ if (GetSavedWindowPlacement(&saved_bounds, &saved_show_state_)) {
+ if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED) {
+ // If we're going to maximize, wait until Show is invoked to set the
+ // bounds. That way we avoid a noticeable resize.
+ initial_restored_bounds_ = saved_bounds;
+ } else if (!saved_bounds.IsEmpty()) {
+ // If the saved bounds are valid, use them.
+ SetBounds(saved_bounds);
+ }
+ } else {
+ if (bounds.IsEmpty()) {
+ // No initial bounds supplied, so size the window to its content and
+ // center over its parent.
+ native_widget_->CenterWindow(non_client_view_->GetPreferredSize());
+ } else {
+ // Use the supplied initial bounds.
+ SetBoundsConstrained(bounds);
+ }
+ }
+}
+
+void Widget::SetInitialBoundsForFramelessWindow(const gfx::Rect& bounds) {
+ if (bounds.IsEmpty()) {
+ View* contents_view = GetContentsView();
+ DCHECK(contents_view);
+ // No initial bounds supplied, so size the window to its content and
+ // center over its parent if preferred size is provided.
+ gfx::Size size = contents_view->GetPreferredSize();
+ if (!size.IsEmpty())
+ native_widget_->CenterWindow(size);
+ } else {
+ // Use the supplied initial bounds.
+ SetBoundsConstrained(bounds);
+ }
+}
+
+bool Widget::GetSavedWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) {
+ // First we obtain the window's saved show-style and store it. We need to do
+ // this here, rather than in Show() because by the time Show() is called,
+ // the window's size will have been reset (below) and the saved maximized
+ // state will have been lost. Sadly there's no way to tell on Windows when
+ // a window is restored from maximized state, so we can't more accurately
+ // track maximized state independently of sizing information.
+
+ // Restore the window's placement from the controller.
+ if (widget_delegate_->GetSavedWindowPlacement(bounds, show_state)) {
+ if (!widget_delegate_->ShouldRestoreWindowSize()) {
+ bounds->set_size(non_client_view_->GetPreferredSize());
+ } else {
+ gfx::Size minimum_size = GetMinimumSize();
+ // Make sure the bounds are at least the minimum size.
+ if (bounds->width() < minimum_size.width())
+ bounds->set_width(minimum_size.width());
+
+ if (bounds->height() < minimum_size.height())
+ bounds->set_height(minimum_size.height());
+ }
+ return true;
+ }
+ return false;
+}
+
+scoped_ptr<InputMethod> Widget::CreateInputMethod() {
+ scoped_ptr<InputMethod> input_method(native_widget_->CreateInputMethod());
+ if (input_method.get())
+ input_method->Init(this);
+ return input_method.Pass();
+}
+
+void Widget::ReplaceInputMethod(InputMethod* input_method) {
+ input_method_.reset(input_method);
+ input_method->SetDelegate(native_widget_->GetInputMethodDelegate());
+ input_method->Init(this);
+}
+
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// internal::NativeWidgetPrivate, NativeWidget implementation:
+
+internal::NativeWidgetPrivate* NativeWidgetPrivate::AsNativeWidgetPrivate() {
+ return this;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
new file mode 100644
index 00000000000..f020a0c7de1
--- /dev/null
+++ b/chromium/ui/views/widget/widget.h
@@ -0,0 +1,858 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_WIDGET_H_
+#define UI_VIEWS_WIDGET_WIDGET_H_
+
+#include <set>
+#include <stack>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/compositor/layer_type.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/widget/native_widget_delegate.h"
+#include "ui/views/window/client_view.h"
+#include "ui/views/window/non_client_view.h"
+
+#if defined(OS_WIN)
+// Windows headers define macros for these function names which screw with us.
+#if defined(IsMaximized)
+#undef IsMaximized
+#endif
+#if defined(IsMinimized)
+#undef IsMinimized
+#endif
+#if defined(CreateWindow)
+#undef CreateWindow
+#endif
+#endif
+
+namespace gfx {
+class Canvas;
+class Point;
+class Rect;
+}
+
+namespace ui {
+class Accelerator;
+class Compositor;
+class DefaultThemeProvider;
+class Layer;
+class NativeTheme;
+class OSExchangeData;
+class ThemeProvider;
+}
+
+namespace views {
+
+class DesktopRootWindowHost;
+class InputMethod;
+class NativeWidget;
+class NonClientFrameView;
+class View;
+class WidgetDelegate;
+class WidgetObserver;
+
+namespace internal {
+class NativeWidgetPrivate;
+class RootView;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget class
+//
+// Encapsulates the platform-specific rendering, event receiving and widget
+// management aspects of the UI framework.
+//
+// Owns a RootView and thus a View hierarchy. Can contain child Widgets.
+// Widget is a platform-independent type that communicates with a platform or
+// context specific NativeWidget implementation.
+//
+// A special note on ownership:
+//
+// Depending on the value of the InitParams' ownership field, the Widget
+// either owns or is owned by its NativeWidget:
+//
+// ownership = NATIVE_WIDGET_OWNS_WIDGET (default)
+// The Widget instance is owned by its NativeWidget. When the NativeWidget
+// is destroyed (in response to a native destruction message), it deletes
+// the Widget from its destructor.
+// ownership = WIDGET_OWNS_NATIVE_WIDGET (non-default)
+// The Widget instance owns its NativeWidget. This state implies someone
+// else wants to control the lifetime of this object. When they destroy
+// the Widget it is responsible for destroying the NativeWidget (from its
+// destructor).
+//
+class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
+ public FocusTraversable {
+ public:
+ typedef std::set<Widget*> Widgets;
+
+ enum FrameType {
+ FRAME_TYPE_DEFAULT, // Use whatever the default would be.
+ FRAME_TYPE_FORCE_CUSTOM, // Force the custom frame.
+ FRAME_TYPE_FORCE_NATIVE // Force the native frame.
+ };
+
+ // Result from RunMoveLoop().
+ enum MoveLoopResult {
+ // The move loop completed successfully.
+ MOVE_LOOP_SUCCESSFUL,
+
+ // The user canceled the move loop.
+ MOVE_LOOP_CANCELED
+ };
+
+ // Source that initiated the move loop.
+ enum MoveLoopSource {
+ MOVE_LOOP_SOURCE_MOUSE,
+ MOVE_LOOP_SOURCE_TOUCH,
+ };
+
+ struct VIEWS_EXPORT InitParams {
+ enum Type {
+ TYPE_WINDOW, // A decorated Window, like a frame window.
+ // Widgets of TYPE_WINDOW will have a NonClientView.
+ TYPE_PANEL, // Always on top window managed by PanelManager.
+ // Widgets of TYPE_PANEL will have a NonClientView.
+ TYPE_WINDOW_FRAMELESS,
+ // An undecorated Window.
+ TYPE_CONTROL, // A control, like a button.
+ TYPE_POPUP, // An undecorated Window, with transient properties.
+ TYPE_MENU, // An undecorated Window, with transient properties
+ // specialized to menus.
+ TYPE_TOOLTIP,
+ TYPE_BUBBLE,
+ };
+
+ enum WindowOpacity {
+ // Infer fully opaque or not. For WinAura, top-level windows that are not
+ // of TYPE_WINDOW are translucent so that they can be made to fade in. In
+ // all other cases, windows are fully opaque.
+ INFER_OPACITY,
+ // Fully opaque.
+ OPAQUE_WINDOW,
+ // Possibly translucent/transparent.
+ TRANSLUCENT_WINDOW,
+ };
+
+ enum Ownership {
+ // Default. Creator is not responsible for managing the lifetime of the
+ // Widget, it is destroyed when the corresponding NativeWidget is
+ // destroyed.
+ NATIVE_WIDGET_OWNS_WIDGET,
+ // Used when the Widget is owned by someone other than the NativeWidget,
+ // e.g. a scoped_ptr in tests.
+ WIDGET_OWNS_NATIVE_WIDGET
+ };
+
+ InitParams();
+ explicit InitParams(Type type);
+
+
+ // Will return the first of the following that isn't NULL: the native view,
+ // |parent|, |context|.
+ gfx::NativeView GetContext() const;
+
+ Type type;
+ // If NULL, a default implementation will be constructed.
+ WidgetDelegate* delegate;
+ bool child;
+ // If TRANSLUCENT_WINDOW, the widget may be fully or partially transparent.
+ // If OPAQUE_WINDOW, we can perform optimizations based on the widget being
+ // fully opaque. Defaults to TRANSLUCENT_WINDOW if
+ // ViewsDelegate::UseTransparentWindows(). Defaults to OPAQUE_WINDOW for
+ // non-window widgets.
+ WindowOpacity opacity;
+ bool accept_events;
+ bool can_activate;
+ bool keep_on_top;
+ Ownership ownership;
+ bool mirror_origin_in_rtl;
+ bool has_dropshadow;
+ // Only used by NativeWidgetWin. Specifies that the system default caption
+ // and icon should not be rendered, and that the client area should be
+ // equivalent to the window area.
+ bool remove_standard_frame;
+ // Only used by ShellWindow on Windows. Specifies that the default icon of
+ // packaged app should be the system default icon.
+ bool use_system_default_icon;
+ // Whether the widget should be maximized or minimized.
+ ui::WindowShowState show_state;
+ // Should the widget be double buffered? Default is false.
+ bool double_buffer;
+ gfx::NativeView parent;
+ // Specifies the initial bounds of the Widget. Default is empty, which means
+ // the NativeWidget may specify a default size. If the parent is specified,
+ // |bounds| is in the parent's coordinate system. If the parent is not
+ // specified, it's in screen's global coordinate system.
+ gfx::Rect bounds;
+ // When set, this value is used as the Widget's NativeWidget implementation.
+ // The Widget will not construct a default one. Default is NULL.
+ NativeWidget* native_widget;
+ // Aura-only. Provides a DesktopRootWindowHost implementation to use instead
+ // of the default one.
+ // TODO(beng): Figure out if there's a better way to expose this, e.g. get
+ // rid of NW subclasses and do this all via message handling.
+ DesktopRootWindowHost* desktop_root_window_host;
+ // Whether this window is intended to be a toplevel window with no
+ // attachment to any other window. (This may be a transient window if
+ // |parent| is set.)
+ bool top_level;
+ // Only used by NativeWidgetAura. Specifies the type of layer for the
+ // aura::Window. Default is LAYER_TEXTURED.
+ ui::LayerType layer_type;
+ // Only used by Aura. Provides a context window whose RootWindow is
+ // consulted during widget creation to determine where in the Window
+ // hierarchy this widget should be placed. (This is separate from |parent|;
+ // if you pass a RootWindow to |parent|, your window will be parented to
+ // |parent|. If you pass a RootWindow to |context|, we ask that RootWindow
+ // where it wants your window placed.) NULL is not allowed if you are using
+ // aura.
+ gfx::NativeView context;
+ };
+
+ Widget();
+ virtual ~Widget();
+
+ // Creates a toplevel window with no context. These methods should only be
+ // used in cases where there is no contextual information because we're
+ // creating a toplevel window connected to no other event.
+ //
+ // If you have any parenting or context information, or can pass that
+ // information, prefer the WithParent or WithContext versions of these
+ // methods.
+ static Widget* CreateWindow(WidgetDelegate* delegate);
+ static Widget* CreateWindowWithBounds(WidgetDelegate* delegate,
+ const gfx::Rect& bounds);
+
+ // Creates a decorated window Widget with the specified properties.
+ static Widget* CreateWindowWithParent(WidgetDelegate* delegate,
+ gfx::NativeWindow parent);
+ static Widget* CreateWindowWithParentAndBounds(WidgetDelegate* delegate,
+ gfx::NativeWindow parent,
+ const gfx::Rect& bounds);
+
+ // Creates a decorated window Widget in the same desktop context as
+ // |context|.
+ static Widget* CreateWindowWithContext(WidgetDelegate* delegate,
+ gfx::NativeView context);
+ static Widget* CreateWindowWithContextAndBounds(WidgetDelegate* delegate,
+ gfx::NativeView context,
+ const gfx::Rect& bounds);
+
+
+ // Enumerates all windows pertaining to us and notifies their
+ // view hierarchies that the locale has changed.
+ // TODO(beng): remove post-Aurafication of ChromeOS.
+ static void NotifyLocaleChanged();
+
+ // Closes all Widgets that aren't identified as "secondary widgets". Called
+ // during application shutdown when the last non-secondary widget is closed.
+ static void CloseAllSecondaryWidgets();
+
+ // Converts a rectangle from one Widget's coordinate system to another's.
+ // Returns false if the conversion couldn't be made, because either these two
+ // Widgets do not have a common ancestor or they are not on the screen yet.
+ // The value of |*rect| won't be changed when false is returned.
+ static bool ConvertRect(const Widget* source,
+ const Widget* target,
+ gfx::Rect* rect);
+
+ // Retrieves the Widget implementation associated with the given
+ // NativeView or Window, or NULL if the supplied handle has no associated
+ // Widget.
+ static Widget* GetWidgetForNativeView(gfx::NativeView native_view);
+ static Widget* GetWidgetForNativeWindow(gfx::NativeWindow native_window);
+
+ // Retrieves the top level widget in a native view hierarchy
+ // starting at |native_view|. Top level widget is a widget with TYPE_WINDOW,
+ // TYPE_PANEL, TYPE_WINDOW_FRAMELESS, POPUP or MENU and has its own
+ // focus manager. This may be itself if the |native_view| is top level,
+ // or NULL if there is no toplevel in a native view hierarchy.
+ static Widget* GetTopLevelWidgetForNativeView(gfx::NativeView native_view);
+
+ // Returns all Widgets in |native_view|'s hierarchy, including itself if
+ // it is one.
+ static void GetAllChildWidgets(gfx::NativeView native_view,
+ Widgets* children);
+
+ // Re-parent a NativeView and notify all Widgets in |native_view|'s hierarchy
+ // of the change.
+ static void ReparentNativeView(gfx::NativeView native_view,
+ gfx::NativeView new_parent);
+
+ // Returns the preferred size of the contents view of this window based on
+ // its localized size data. The width in cols is held in a localized string
+ // resource identified by |col_resource_id|, the height in the same fashion.
+ // TODO(beng): This should eventually live somewhere else, probably closer to
+ // ClientView.
+ static int GetLocalizedContentsWidth(int col_resource_id);
+ static int GetLocalizedContentsHeight(int row_resource_id);
+ static gfx::Size GetLocalizedContentsSize(int col_resource_id,
+ int row_resource_id);
+
+ // Returns true if the specified type requires a NonClientView.
+ static bool RequiresNonClientView(InitParams::Type type);
+
+ void Init(const InitParams& params);
+
+ // Returns the gfx::NativeView associated with this Widget.
+ gfx::NativeView GetNativeView() const;
+
+ // Returns the gfx::NativeWindow associated with this Widget. This may return
+ // NULL on some platforms if the widget was created with a type other than
+ // TYPE_WINDOW or TYPE_PANEL.
+ gfx::NativeWindow GetNativeWindow() const;
+
+ // Add/remove observer.
+ void AddObserver(WidgetObserver* observer);
+ void RemoveObserver(WidgetObserver* observer);
+ bool HasObserver(WidgetObserver* observer);
+
+ // Returns the accelerator given a command id. Returns false if there is
+ // no accelerator associated with a given id, which is a common condition.
+ virtual bool GetAccelerator(int cmd_id, ui::Accelerator* accelerator);
+
+ // Forwarded from the RootView so that the widget can do any cleanup.
+ void ViewHierarchyChanged(const View::ViewHierarchyChangedDetails& details);
+
+ // Performs any necessary cleanup and forwards to RootView.
+ void NotifyNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view);
+
+ // Returns the top level widget in a hierarchy (see is_top_level() for
+ // the definition of top level widget.) Will return NULL if called
+ // before the widget is attached to the top level widget's hierarchy.
+ Widget* GetTopLevelWidget();
+ const Widget* GetTopLevelWidget() const;
+
+ // Gets/Sets the WidgetDelegate.
+ WidgetDelegate* widget_delegate() const { return widget_delegate_; }
+
+ // Sets the specified view as the contents of this Widget. There can only
+ // be one contents view child of this Widget's RootView. This view is sized to
+ // fit the entire size of the RootView. The RootView takes ownership of this
+ // View, unless it is set as not being parent-owned.
+ void SetContentsView(View* view);
+ View* GetContentsView();
+
+ // Returns the bounds of the Widget in screen coordinates.
+ gfx::Rect GetWindowBoundsInScreen() const;
+
+ // Returns the bounds of the Widget's client area in screen coordinates.
+ gfx::Rect GetClientAreaBoundsInScreen() const;
+
+ // Retrieves the restored bounds for the window.
+ gfx::Rect GetRestoredBounds() const;
+
+ // Sizes and/or places the widget to the specified bounds, size or position.
+ void SetBounds(const gfx::Rect& bounds);
+ void SetSize(const gfx::Size& size);
+
+ // Sizes the window to the specified size and centerizes it.
+ void CenterWindow(const gfx::Size& size);
+
+ // Like SetBounds(), but ensures the Widget is fully visible on screen,
+ // resizing and/or repositioning as necessary. This is only useful for
+ // non-child widgets.
+ void SetBoundsConstrained(const gfx::Rect& bounds);
+
+ // Sets whether animations that occur when visibility is changed are enabled.
+ // Default is true.
+ void SetVisibilityChangedAnimationsEnabled(bool value);
+
+ // Starts a nested message loop that moves the window. This can be used to
+ // start a window move operation from a mouse or touch event. This returns
+ // when the move completes. |drag_offset| is the offset from the top left
+ // corner of the window to the point where the cursor is dragging, and is used
+ // to offset the bounds of the window from the cursor.
+ MoveLoopResult RunMoveLoop(const gfx::Vector2d& drag_offset,
+ MoveLoopSource source);
+
+ // Stops a previously started move loop. This is not immediate.
+ void EndMoveLoop();
+
+ // Places the widget in front of the specified widget in z-order.
+ void StackAboveWidget(Widget* widget);
+ void StackAbove(gfx::NativeView native_view);
+ void StackAtTop();
+
+ // Places the widget below the specified NativeView.
+ void StackBelow(gfx::NativeView native_view);
+
+ // Sets a shape on the widget. This takes ownership of shape.
+ void SetShape(gfx::NativeRegion shape);
+
+ // Hides the widget then closes it after a return to the message loop.
+ virtual void Close();
+
+ // TODO(beng): Move off public API.
+ // Closes the widget immediately. Compare to |Close|. This will destroy the
+ // window handle associated with this Widget, so should not be called from
+ // any code that expects it to be valid beyond this call.
+ void CloseNow();
+
+ // Whether the widget has been asked to close itself. In particular this is
+ // set to true after Close() has been invoked on the NativeWidget.
+ bool IsClosed() const;
+
+ // Shows or hides the widget, without changing activation state.
+ virtual void Show();
+ void Hide();
+
+ // Like Show(), but does not activate the window.
+ void ShowInactive();
+
+ // Activates the widget, assuming it already exists and is visible.
+ void Activate();
+
+ // Deactivates the widget, making the next window in the Z order the active
+ // window.
+ void Deactivate();
+
+ // Returns whether the Widget is the currently active window.
+ virtual bool IsActive() const;
+
+ // Prevents the window from being rendered as deactivated. This state is
+ // reset automatically as soon as the window becomes activated again. There is
+ // no ability to control the state through this API as this leads to sync
+ // problems.
+ void DisableInactiveRendering();
+
+ // Sets the widget to be on top of all other widgets in the windowing system.
+ void SetAlwaysOnTop(bool on_top);
+
+ // Maximizes/minimizes/restores the window.
+ void Maximize();
+ void Minimize();
+ void Restore();
+
+ // Whether or not the window is maximized or minimized.
+ virtual bool IsMaximized() const;
+ bool IsMinimized() const;
+
+ // Accessors for fullscreen state.
+ void SetFullscreen(bool fullscreen);
+ bool IsFullscreen() const;
+
+ // Sets the opacity of the widget. This may allow widgets behind the widget
+ // in the Z-order to become visible, depending on the capabilities of the
+ // underlying windowing system.
+ void SetOpacity(unsigned char opacity);
+
+ // Sets whether or not the window should show its frame as a "transient drag
+ // frame" - slightly transparent and without the standard window controls.
+ void SetUseDragFrame(bool use_drag_frame);
+
+ // Flashes the frame of the window to draw attention to it. Currently only
+ // implemented on Windows for non-Aura.
+ void FlashFrame(bool flash);
+
+ // Returns the View at the root of the View hierarchy contained by this
+ // Widget.
+ View* GetRootView();
+ const View* GetRootView() const;
+
+ // A secondary widget is one that is automatically closed (via Close()) when
+ // all non-secondary widgets are closed.
+ // Default is true.
+ // TODO(beng): This is an ugly API, should be handled implicitly via
+ // transience.
+ void set_is_secondary_widget(bool is_secondary_widget) {
+ is_secondary_widget_ = is_secondary_widget;
+ }
+ bool is_secondary_widget() const { return is_secondary_widget_; }
+
+ // Returns whether the Widget is visible to the user.
+ virtual bool IsVisible() const;
+
+ // Returns the ThemeProvider that provides theme resources for this Widget.
+ virtual ui::ThemeProvider* GetThemeProvider() const;
+
+ ui::NativeTheme* GetNativeTheme() {
+ return const_cast<ui::NativeTheme*>(
+ const_cast<const Widget*>(this)->GetNativeTheme());
+ }
+ const ui::NativeTheme* GetNativeTheme() const;
+
+ // Returns the FocusManager for this widget.
+ // Note that all widgets in a widget hierarchy share the same focus manager.
+ FocusManager* GetFocusManager();
+ const FocusManager* GetFocusManager() const;
+
+ // Returns the InputMethod for this widget.
+ // Note that all widgets in a widget hierarchy share the same input method.
+ InputMethod* GetInputMethod();
+ const InputMethod* GetInputMethod() const;
+
+ // Starts a drag operation for the specified view. This blocks until the drag
+ // operation completes. |view| can be NULL.
+ // If the view is non-NULL it can be accessed during the drag by calling
+ // dragged_view(). If the view has not been deleted during the drag,
+ // OnDragDone() is called on it. |location| is in the widget's coordinate
+ // system.
+ void RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source);
+
+ // Returns the view that requested the current drag operation via
+ // RunShellDrag(), or NULL if there is no such view or drag operation.
+ View* dragged_view() { return dragged_view_; }
+
+ // Adds the specified |rect| in client area coordinates to the rectangle to be
+ // redrawn.
+ virtual void SchedulePaintInRect(const gfx::Rect& rect);
+
+ // Sets the currently visible cursor. If |cursor| is NULL, the cursor used
+ // before the current is restored.
+ void SetCursor(gfx::NativeCursor cursor);
+
+ // Returns true if and only if mouse events are enabled.
+ bool IsMouseEventsEnabled() const;
+
+ // Sets/Gets a native window property on the underlying native window object.
+ // Returns NULL if the property does not exist. Setting the property value to
+ // NULL removes the property.
+ void SetNativeWindowProperty(const char* name, void* value);
+ void* GetNativeWindowProperty(const char* name) const;
+
+ // Tell the window to update its title from the delegate.
+ void UpdateWindowTitle();
+
+ // Tell the window to update its icon from the delegate.
+ void UpdateWindowIcon();
+
+ // Retrieves the focus traversable for this widget.
+ FocusTraversable* GetFocusTraversable();
+
+ // Notifies the view hierarchy contained in this widget that theme resources
+ // changed.
+ void ThemeChanged();
+
+ // Notifies the view hierarchy contained in this widget that locale resources
+ // changed.
+ void LocaleChanged();
+
+ void SetFocusTraversableParent(FocusTraversable* parent);
+ void SetFocusTraversableParentView(View* parent_view);
+
+ // Clear native focus set to the Widget's NativeWidget.
+ void ClearNativeFocus();
+
+ void set_frame_type(FrameType frame_type) { frame_type_ = frame_type; }
+ FrameType frame_type() const { return frame_type_; }
+
+ // Creates an appropriate NonClientFrameView for this widget. The
+ // WidgetDelegate is given the first opportunity to create one, followed by
+ // the NativeWidget implementation. If both return NULL, a default one is
+ // created.
+ virtual NonClientFrameView* CreateNonClientFrameView();
+
+ // Whether we should be using a native frame.
+ bool ShouldUseNativeFrame() const;
+
+ // Forces the frame into the alternate frame type (custom or native) depending
+ // on its current state.
+ void DebugToggleFrameType();
+
+ // Tell the window that something caused the frame type to change.
+ void FrameTypeChanged();
+
+ NonClientView* non_client_view() {
+ return const_cast<NonClientView*>(
+ const_cast<const Widget*>(this)->non_client_view());
+ }
+ const NonClientView* non_client_view() const {
+ return non_client_view_;
+ }
+
+ ClientView* client_view() {
+ return const_cast<ClientView*>(
+ const_cast<const Widget*>(this)->client_view());
+ }
+ const ClientView* client_view() const {
+ // non_client_view_ may be NULL, especially during creation.
+ return non_client_view_ ? non_client_view_->client_view() : NULL;
+ }
+
+ const ui::Compositor* GetCompositor() const;
+ ui::Compositor* GetCompositor();
+
+ // Returns the widget's layer, if any.
+ ui::Layer* GetLayer();
+
+ // Reorders the widget's child NativeViews which are associated to the view
+ // tree (eg via a NativeViewHost) to match the z-order of the views in the
+ // view tree. The z-order of views with layers relative to views with
+ // associated NativeViews is used to reorder the NativeView layers. This
+ // method assumes that the widget's child layers which are owned by a view are
+ // already in the correct z-order relative to each other and does no
+ // reordering if there are no views with an associated NativeView.
+ void ReorderNativeViews();
+
+ // Schedules an update to the root layers. The actual processing occurs when
+ // GetRootLayers() is invoked.
+ void UpdateRootLayers();
+
+ const NativeWidget* native_widget() const;
+ NativeWidget* native_widget();
+
+ internal::NativeWidgetPrivate* native_widget_private() {
+ return native_widget_;
+ }
+ const internal::NativeWidgetPrivate* native_widget_private() const {
+ return native_widget_;
+ }
+
+ // Sets capture to the specified view. This makes it so that all mouse, touch
+ // and gesture events go to |view|.
+ void SetCapture(View* view);
+
+ // Releases capture.
+ void ReleaseCapture();
+
+ // Returns true if the widget has capture.
+ bool HasCapture();
+
+ // Invoked when the tooltip text changes for the specified views.
+ void TooltipTextChanged(View* view);
+
+ // Sets-up the focus manager with the view that should have focus when the
+ // window is shown the first time. Returns true if the initial focus has been
+ // set or the widget should not set the initial focus, or false if the caller
+ // should set the initial focus (if any).
+ bool SetInitialFocus();
+
+ void set_focus_on_creation(bool focus_on_creation) {
+ focus_on_creation_ = focus_on_creation;
+ }
+
+ // Returns a View* that any child Widgets backed by NativeWidgetViews
+ // are added to. The default implementation returns the contents view
+ // if it exists and the root view otherwise.
+ virtual View* GetChildViewParent();
+
+ // True if the widget is considered top level widget. Top level widget
+ // is a widget of TYPE_WINDOW, TYPE_PANEL, TYPE_WINDOW_FRAMELESS, BUBBLE,
+ // POPUP or MENU, and has a focus manager and input method object associated
+ // with it. TYPE_CONTROL and TYPE_TOOLTIP is not considered top level.
+ bool is_top_level() const { return is_top_level_; }
+
+ // True when window movement via mouse interaction with the frame is disabled.
+ bool movement_disabled() const { return movement_disabled_; }
+ void set_movement_disabled(bool disabled) { movement_disabled_ = disabled; }
+
+ // Returns the work area bounds of the screen the Widget belongs to.
+ gfx::Rect GetWorkAreaBoundsInScreen() const;
+
+ // Creates and dispatches synthesized mouse move event using the current
+ // mouse location to refresh hovering status in the widget.
+ void SynthesizeMouseMoveEvent();
+
+ // Notification that our owner is closing.
+ // NOTE: this is not invoked for aura as it's currently not needed there.
+ // Under aura menus close by way of activation getting reset when the owner
+ // closes.
+ virtual void OnOwnerClosing();
+
+ // Overridden from NativeWidgetDelegate:
+ virtual bool IsModal() const OVERRIDE;
+ virtual bool IsDialogBox() const OVERRIDE;
+ virtual bool CanActivate() const OVERRIDE;
+ virtual bool IsInactiveRenderingDisabled() const OVERRIDE;
+ virtual void EnableInactiveRendering() OVERRIDE;
+ virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE;
+ virtual void OnNativeFocus(gfx::NativeView old_focused_view) OVERRIDE;
+ virtual void OnNativeBlur(gfx::NativeView new_focused_view) OVERRIDE;
+ virtual void OnNativeWidgetVisibilityChanged(bool visible) OVERRIDE;
+ virtual void OnNativeWidgetCreated(bool desktop_widget) OVERRIDE;
+ virtual void OnNativeWidgetDestroying() OVERRIDE;
+ virtual void OnNativeWidgetDestroyed() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetMaximumSize() OVERRIDE;
+ virtual void OnNativeWidgetMove() OVERRIDE;
+ virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) OVERRIDE;
+ virtual void OnNativeWidgetBeginUserBoundsChange() OVERRIDE;
+ virtual void OnNativeWidgetEndUserBoundsChange() OVERRIDE;
+ virtual bool HasFocusManager() const OVERRIDE;
+ virtual bool OnNativeWidgetPaintAccelerated(
+ const gfx::Rect& dirty_region) OVERRIDE;
+ virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual int GetNonClientComponent(const gfx::Point& point) OVERRIDE;
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnMouseCaptureLost() OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+ virtual bool ExecuteCommand(int command_id) OVERRIDE;
+ virtual InputMethod* GetInputMethodDirect() OVERRIDE;
+ virtual const std::vector<ui::Layer*>& GetRootLayers() OVERRIDE;
+ virtual bool HasHitTestMask() const OVERRIDE;
+ virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
+ virtual Widget* AsWidget() OVERRIDE;
+ virtual const Widget* AsWidget() const OVERRIDE;
+
+ // Overridden from FocusTraversable:
+ virtual FocusSearch* GetFocusSearch() OVERRIDE;
+ virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
+ virtual View* GetFocusTraversableParentView() OVERRIDE;
+
+ protected:
+ // Creates the RootView to be used within this Widget. Subclasses may override
+ // to create custom RootViews that do specialized event processing.
+ // TODO(beng): Investigate whether or not this is needed.
+ virtual internal::RootView* CreateRootView();
+
+ // Provided to allow the NativeWidget implementations to destroy the RootView
+ // _before_ the focus manager/tooltip manager.
+ // TODO(beng): remove once we fold those objects onto this one.
+ void DestroyRootView();
+
+ private:
+ friend class NativeTextfieldViewsTest;
+ friend class NativeComboboxViewsTest;
+
+ // Returns whether capture should be released on mouse release.
+ virtual bool ShouldReleaseCaptureOnMouseReleased() const;
+
+ // Sets the value of |disable_inactive_rendering_|. If the value changes,
+ // both the NonClientView and WidgetDelegate are notified.
+ void SetInactiveRenderingDisabled(bool value);
+
+ // Persists the window's restored position and "show" state using the
+ // window delegate.
+ void SaveWindowPlacement();
+
+ // Sizes and positions the window just after it is created.
+ void SetInitialBounds(const gfx::Rect& bounds);
+
+ // Sizes and positions the frameless window just after it is created.
+ void SetInitialBoundsForFramelessWindow(const gfx::Rect& bounds);
+
+ // Returns the bounds and "show" state from the delegate. Returns true if
+ // the delegate wants to use a specified bounds.
+ bool GetSavedWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state);
+
+ // Creates and initializes a new InputMethod and returns it, otherwise null.
+ scoped_ptr<InputMethod> CreateInputMethod();
+
+ // Sets a different InputMethod instance to this widget. The instance
+ // must not be initialized, the ownership will be assumed by the widget.
+ // It's only for testing purpose.
+ void ReplaceInputMethod(InputMethod* input_method);
+
+ internal::NativeWidgetPrivate* native_widget_;
+
+ ObserverList<WidgetObserver> observers_;
+
+ // Non-owned pointer to the Widget's delegate. May be NULL if no delegate is
+ // being used.
+ WidgetDelegate* widget_delegate_;
+
+ // The root of the View hierarchy attached to this window.
+ // WARNING: see warning in tooltip_manager_ for ordering dependencies with
+ // this and tooltip_manager_.
+ scoped_ptr<internal::RootView> root_view_;
+
+ // The View that provides the non-client area of the window (title bar,
+ // window controls, sizing borders etc). To use an implementation other than
+ // the default, this class must be sub-classed and this value set to the
+ // desired implementation before calling |InitWindow()|.
+ NonClientView* non_client_view_;
+
+ // The focus manager keeping track of focus for this Widget and any of its
+ // children. NULL for non top-level widgets.
+ // WARNING: RootView's destructor calls into the FocusManager. As such, this
+ // must be destroyed AFTER root_view_. This is enforced in DestroyRootView().
+ scoped_ptr<FocusManager> focus_manager_;
+
+ // A theme provider to use when no other theme provider is specified.
+ scoped_ptr<ui::DefaultThemeProvider> default_theme_provider_;
+
+ // Valid for the lifetime of RunShellDrag(), indicates the view the drag
+ // started from.
+ View* dragged_view_;
+
+ // See class documentation for Widget above for a note about ownership.
+ InitParams::Ownership ownership_;
+
+ // See set_is_secondary_widget().
+ bool is_secondary_widget_;
+
+ // The current frame type in use by this window. Defaults to
+ // FRAME_TYPE_DEFAULT.
+ FrameType frame_type_;
+
+ // True when the window should be rendered as active, regardless of whether
+ // or not it actually is.
+ bool disable_inactive_rendering_;
+
+ // Set to true if the widget is in the process of closing.
+ bool widget_closed_;
+
+ // The saved "show" state for this window. See note in SetInitialBounds
+ // that explains why we save this.
+ ui::WindowShowState saved_show_state_;
+
+ // The restored bounds used for the initial show. This is only used if
+ // |saved_show_state_| is maximized.
+ gfx::Rect initial_restored_bounds_;
+
+ // Focus is automatically set to the view provided by the delegate
+ // when the widget is shown. Set this value to false to override
+ // initial focus for the widget.
+ bool focus_on_creation_;
+
+ mutable scoped_ptr<InputMethod> input_method_;
+
+ // See |is_top_level()| accessor.
+ bool is_top_level_;
+
+ // Tracks whether native widget has been initialized.
+ bool native_widget_initialized_;
+
+ // Whether native widget has been destroyed.
+ bool native_widget_destroyed_;
+
+ // TODO(beng): Remove NativeWidgetGtk's dependence on these:
+ // If true, the mouse is currently down.
+ bool is_mouse_button_pressed_;
+
+ // If true, a touch device is currently down.
+ bool is_touch_down_;
+
+ // TODO(beng): Remove NativeWidgetGtk's dependence on these:
+ // The following are used to detect duplicate mouse move events and not
+ // deliver them. Displaying a window may result in the system generating
+ // duplicate move events even though the mouse hasn't moved.
+ bool last_mouse_event_was_move_;
+ gfx::Point last_mouse_event_position_;
+
+ // See description in GetRootLayers().
+ std::vector<ui::Layer*> root_layers_;
+
+ // Is |root_layers_| out of date?
+ bool root_layers_dirty_;
+
+ // True when window movement via mouse interaction with the frame should be
+ // disabled.
+ bool movement_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(Widget);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_H_
diff --git a/chromium/ui/views/widget/widget_aura_utils.cc b/chromium/ui/views/widget/widget_aura_utils.cc
new file mode 100644
index 00000000000..76422e0c52f
--- /dev/null
+++ b/chromium/ui/views/widget/widget_aura_utils.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/widget_aura_utils.h"
+
+#include "base/logging.h"
+
+namespace views {
+
+aura::client::WindowType GetAuraWindowTypeForWidgetType(
+ Widget::InitParams::Type type) {
+ switch (type) {
+ case Widget::InitParams::TYPE_WINDOW:
+ return aura::client::WINDOW_TYPE_NORMAL;
+ case Widget::InitParams::TYPE_PANEL:
+ return aura::client::WINDOW_TYPE_PANEL;
+ case Widget::InitParams::TYPE_CONTROL:
+ return aura::client::WINDOW_TYPE_CONTROL;
+ case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
+ case Widget::InitParams::TYPE_POPUP:
+ case Widget::InitParams::TYPE_BUBBLE:
+ return aura::client::WINDOW_TYPE_POPUP;
+ case Widget::InitParams::TYPE_MENU:
+ return aura::client::WINDOW_TYPE_MENU;
+ case Widget::InitParams::TYPE_TOOLTIP:
+ return aura::client::WINDOW_TYPE_TOOLTIP;
+ default:
+ NOTREACHED() << "Unhandled widget type " << type;
+ return aura::client::WINDOW_TYPE_UNKNOWN;
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/widget_aura_utils.h b/chromium/ui/views/widget/widget_aura_utils.h
new file mode 100644
index 00000000000..8f0bfcc0358
--- /dev/null
+++ b/chromium/ui/views/widget/widget_aura_utils.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_WIDGET_AURA_UTILS_H_
+#define UI_VIEWS_WIDGET_WIDGET_AURA_UTILS_H_
+
+#include "ui/aura/client/window_types.h"
+#include "ui/views/widget/widget.h"
+
+// Functions shared by native_widget_aura.cc and desktop_native_widget_aura.cc:
+
+namespace views {
+
+aura::client::WindowType GetAuraWindowTypeForWidgetType(
+ Widget::InitParams::Type type);
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_AURA_UTILS_H_
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
new file mode 100644
index 00000000000..dcb7c361030
--- /dev/null
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/widget_delegate.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/view.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/client_view.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// WidgetDelegate:
+
+WidgetDelegate::WidgetDelegate() : default_contents_view_(NULL) {
+}
+
+void WidgetDelegate::OnWidgetMove() {
+}
+
+void WidgetDelegate::OnDisplayChanged() {
+}
+
+void WidgetDelegate::OnWorkAreaChanged() {
+}
+
+View* WidgetDelegate::GetInitiallyFocusedView() {
+ return NULL;
+}
+
+BubbleDelegateView* WidgetDelegate::AsBubbleDelegate() {
+ return NULL;
+}
+
+DialogDelegate* WidgetDelegate::AsDialogDelegate() {
+ return NULL;
+}
+
+bool WidgetDelegate::CanResize() const {
+ return false;
+}
+
+bool WidgetDelegate::CanMaximize() const {
+ return false;
+}
+
+bool WidgetDelegate::CanActivate() const {
+ return true;
+}
+
+ui::ModalType WidgetDelegate::GetModalType() const {
+ return ui::MODAL_TYPE_NONE;
+}
+
+ui::AccessibilityTypes::Role WidgetDelegate::GetAccessibleWindowRole() const {
+ return ui::AccessibilityTypes::ROLE_WINDOW;
+}
+
+string16 WidgetDelegate::GetAccessibleWindowTitle() const {
+ return GetWindowTitle();
+}
+
+string16 WidgetDelegate::GetWindowTitle() const {
+ return string16();
+}
+
+bool WidgetDelegate::ShouldShowWindowTitle() const {
+ return true;
+}
+
+bool WidgetDelegate::ShouldShowCloseButton() const {
+ return true;
+}
+
+bool WidgetDelegate::ShouldHandleSystemCommands() const {
+ const Widget* widget = GetWidget();
+ if (!widget)
+ return false;
+
+ return widget->non_client_view() != NULL;
+}
+
+gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() {
+ // Use the window icon as app icon by default.
+ return GetWindowIcon();
+}
+
+// Returns the icon to be displayed in the window.
+gfx::ImageSkia WidgetDelegate::GetWindowIcon() {
+ return gfx::ImageSkia();
+}
+
+bool WidgetDelegate::ShouldShowWindowIcon() const {
+ return false;
+}
+
+bool WidgetDelegate::ExecuteWindowsCommand(int command_id) {
+ return false;
+}
+
+std::string WidgetDelegate::GetWindowName() const {
+ return std::string();
+}
+
+void WidgetDelegate::SaveWindowPlacement(const gfx::Rect& bounds,
+ ui::WindowShowState show_state) {
+ std::string window_name = GetWindowName();
+ if (!ViewsDelegate::views_delegate || window_name.empty())
+ return;
+
+ ViewsDelegate::views_delegate->SaveWindowPlacement(
+ GetWidget(), window_name, bounds, show_state);
+}
+
+bool WidgetDelegate::GetSavedWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ std::string window_name = GetWindowName();
+ if (!ViewsDelegate::views_delegate || window_name.empty())
+ return false;
+
+ return ViewsDelegate::views_delegate->GetSavedWindowPlacement(
+ window_name, bounds, show_state);
+}
+
+bool WidgetDelegate::ShouldRestoreWindowSize() const {
+ return true;
+}
+
+View* WidgetDelegate::GetContentsView() {
+ if (!default_contents_view_)
+ default_contents_view_ = new View;
+ return default_contents_view_;
+}
+
+ClientView* WidgetDelegate::CreateClientView(Widget* widget) {
+ return new ClientView(widget, GetContentsView());
+}
+
+NonClientFrameView* WidgetDelegate::CreateNonClientFrameView(Widget* widget) {
+ return NULL;
+}
+
+View* WidgetDelegate::CreateOverlayView() {
+ return NULL;
+}
+
+bool WidgetDelegate::WillProcessWorkAreaChange() const {
+ return false;
+}
+
+bool WidgetDelegate::WidgetHasHitTestMask() const {
+ return false;
+}
+
+void WidgetDelegate::GetWidgetHitTestMask(gfx::Path* mask) const {
+ DCHECK(mask);
+}
+
+bool WidgetDelegate::ShouldDescendIntoChildForEventHandling(
+ gfx::NativeView child,
+ const gfx::Point& location) {
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WidgetDelegateView:
+
+WidgetDelegateView::WidgetDelegateView() {
+ // A WidgetDelegate should be deleted on DeleteDelegate.
+ set_owned_by_client();
+}
+
+WidgetDelegateView::~WidgetDelegateView() {
+}
+
+void WidgetDelegateView::DeleteDelegate() {
+ delete this;
+}
+
+Widget* WidgetDelegateView::GetWidget() {
+ return View::GetWidget();
+}
+
+const Widget* WidgetDelegateView::GetWidget() const {
+ return View::GetWidget();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
new file mode 100644
index 00000000000..f465ffb3bc1
--- /dev/null
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_WIDGET_DELEGATE_H_
+#define UI_VIEWS_WIDGET_WIDGET_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/view.h"
+
+namespace gfx {
+class ImageSkia;
+class Rect;
+}
+
+namespace views {
+class BubbleDelegateView;
+class ClientView;
+class DialogDelegate;
+class NonClientFrameView;
+class View;
+class Widget;
+
+// Handles events on Widgets in context-specific ways.
+class VIEWS_EXPORT WidgetDelegate {
+ public:
+ WidgetDelegate();
+
+ // Called whenever the widget's position changes.
+ virtual void OnWidgetMove();
+
+ // Called with the display changes (color depth or resolution).
+ virtual void OnDisplayChanged();
+
+ // Called when the work area (the desktop area minus task bars,
+ // menu bars, etc.) changes in size.
+ virtual void OnWorkAreaChanged();
+
+ // Returns the view that should have the focus when the widget is shown. If
+ // NULL no view is focused.
+ virtual View* GetInitiallyFocusedView();
+
+ virtual BubbleDelegateView* AsBubbleDelegate();
+ virtual DialogDelegate* AsDialogDelegate();
+
+ // Returns true if the window can ever be resized.
+ virtual bool CanResize() const;
+
+ // Returns true if the window can ever be maximized.
+ virtual bool CanMaximize() const;
+
+ // Returns true if the window can be activated.
+ virtual bool CanActivate() const;
+
+ // Returns the modal type that applies to the widget. Default is
+ // ui::MODAL_TYPE_NONE (not modal).
+ virtual ui::ModalType GetModalType() const;
+
+ virtual ui::AccessibilityTypes::Role GetAccessibleWindowRole() const;
+
+ // Returns the title to be read with screen readers.
+ virtual string16 GetAccessibleWindowTitle() const;
+
+ // Returns the text to be displayed in the window title.
+ virtual string16 GetWindowTitle() const;
+
+ // Returns true if the window should show a title in the title bar.
+ virtual bool ShouldShowWindowTitle() const;
+
+ // Returns true if the window should show a close button in the title bar.
+ virtual bool ShouldShowCloseButton() const;
+
+ // Returns true if the window should handle standard system commands, such as
+ // close, minimize, maximize.
+ virtual bool ShouldHandleSystemCommands() const;
+
+ // Returns the app icon for the window. On Windows, this is the ICON_BIG used
+ // in Alt-Tab list and Win7's taskbar.
+ virtual gfx::ImageSkia GetWindowAppIcon();
+
+ // Returns the icon to be displayed in the window.
+ virtual gfx::ImageSkia GetWindowIcon();
+
+ // Returns true if a window icon should be shown.
+ virtual bool ShouldShowWindowIcon() const;
+
+ // Execute a command in the window's controller. Returns true if the command
+ // was handled, false if it was not.
+ virtual bool ExecuteWindowsCommand(int command_id);
+
+ // Returns the window's name identifier. Used to identify this window for
+ // state restoration.
+ virtual std::string GetWindowName() const;
+
+ // Saves the window's bounds and "show" state. By default this uses the
+ // process' local state keyed by window name (See GetWindowName above). This
+ // behavior can be overridden to provide additional functionality.
+ virtual void SaveWindowPlacement(const gfx::Rect& bounds,
+ ui::WindowShowState show_state);
+
+ // Retrieves the window's bounds and "show" states.
+ // This behavior can be overridden to provide additional functionality.
+ virtual bool GetSavedWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const;
+
+ // Returns true if the window's size should be restored. If this is false,
+ // only the window's origin is restored and the window is given its
+ // preferred size.
+ // Default is true.
+ virtual bool ShouldRestoreWindowSize() const;
+
+ // Called when the window closes. The delegate MUST NOT delete itself during
+ // this call, since it can be called afterwards. See DeleteDelegate().
+ virtual void WindowClosing() {}
+
+ // Called when the window is destroyed. No events must be sent or received
+ // after this point. The delegate can use this opportunity to delete itself at
+ // this time if necessary.
+ virtual void DeleteDelegate() {}
+
+ // Called when the user begins/ends to change the bounds of the window.
+ virtual void OnWindowBeginUserBoundsChange() {}
+ virtual void OnWindowEndUserBoundsChange() {}
+
+ // Returns the Widget associated with this delegate.
+ virtual Widget* GetWidget() = 0;
+ virtual const Widget* GetWidget() const = 0;
+
+ // Returns the View that is contained within this Widget.
+ virtual View* GetContentsView();
+
+ // Called by the Widget to create the Client View used to host the contents
+ // of the widget.
+ virtual ClientView* CreateClientView(Widget* widget);
+
+ // Called by the Widget to create the NonClient Frame View for this widget.
+ // Return NULL to use the default one.
+ virtual NonClientFrameView* CreateNonClientFrameView(Widget* widget);
+
+ // Called by the Widget to create the overlay View for this widget. Return
+ // NULL for no overlay. The overlay View will fill the Widget and sit on top
+ // of the ClientView and NonClientFrameView (both visually and wrt click
+ // targeting).
+ virtual View* CreateOverlayView();
+
+ // Returns true if the window can be notified with the work area change.
+ // Otherwise, the work area change for the top window will be processed by
+ // the default window manager. In some cases, like panel, we would like to
+ // manage the positions by ourselves.
+ virtual bool WillProcessWorkAreaChange() const;
+
+ // Returns true if window has a hit-test mask.
+ virtual bool WidgetHasHitTestMask() const;
+
+ // Provides the hit-test mask if HasHitTestMask above returns true.
+ virtual void GetWidgetHitTestMask(gfx::Path* mask) const;
+
+ // Returns true if event handling should descend into |child|.
+ // |location| is in terms of the Window.
+ virtual bool ShouldDescendIntoChildForEventHandling(
+ gfx::NativeView child,
+ const gfx::Point& location);
+
+ // Populates |panes| with accessible panes in this window that can
+ // be cycled through with keyboard focus.
+ virtual void GetAccessiblePanes(std::vector<View*>* panes) {}
+
+ protected:
+ virtual ~WidgetDelegate() {}
+
+ private:
+ View* default_contents_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetDelegate);
+};
+
+// A WidgetDelegate implementation that is-a View. Used to override GetWidget()
+// to call View's GetWidget() for the common case where a WidgetDelegate
+// implementation is-a View. Note that WidgetDelegateView is not owned by
+// view's hierarchy and is expected to be deleted on DeleteDelegate call.
+class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View {
+ public:
+ WidgetDelegateView();
+ virtual ~WidgetDelegateView();
+
+ // Overridden from WidgetDelegate:
+ virtual void DeleteDelegate() OVERRIDE;
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual const Widget* GetWidget() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WidgetDelegateView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_DELEGATE_H_
diff --git a/chromium/ui/views/widget/widget_deletion_observer.cc b/chromium/ui/views/widget/widget_deletion_observer.cc
new file mode 100644
index 00000000000..db3a44e7d8e
--- /dev/null
+++ b/chromium/ui/views/widget/widget_deletion_observer.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2013 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/views/widget/widget_deletion_observer.h"
+
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+WidgetDeletionObserver::WidgetDeletionObserver(Widget* widget)
+ : widget_(widget) {
+ if (widget_)
+ widget_->AddObserver(this);
+}
+
+WidgetDeletionObserver::~WidgetDeletionObserver() {
+ CleanupWidget();
+}
+
+void WidgetDeletionObserver::OnWidgetDestroying(Widget* widget) {
+ CleanupWidget();
+}
+
+void WidgetDeletionObserver::CleanupWidget() {
+ if (widget_) {
+ widget_->RemoveObserver(this);
+ widget_ = NULL;
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/widget_deletion_observer.h b/chromium/ui/views/widget/widget_deletion_observer.h
new file mode 100644
index 00000000000..1956e7f1aec
--- /dev/null
+++ b/chromium/ui/views/widget/widget_deletion_observer.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 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_VIEWS_WIDGET_WIDGET_DELETION_OBSERVER_H_
+#define UI_VIEWS_WIDGET_WIDGET_DELETION_OBSERVER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+class Widget;
+
+// A simple WidgetObserver that can be probed for the life of a widget.
+class WidgetDeletionObserver : public WidgetObserver {
+ public:
+ explicit WidgetDeletionObserver(Widget* widget);
+ virtual ~WidgetDeletionObserver();
+
+ // Returns true if the widget passed in the constructor is still alive.
+ bool IsWidgetAlive() { return widget_ != NULL; }
+
+ // Overridden from WidgetObserver.
+ virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
+
+ private:
+ void CleanupWidget();
+
+ Widget* widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetDeletionObserver);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_DELETION_OBSERVER_H_
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc
new file mode 100644
index 00000000000..53588c25e5e
--- /dev/null
+++ b/chromium/ui/views/widget/widget_hwnd_utils.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/widget_hwnd_utils.h"
+
+#include <dwmapi.h>
+
+#include "base/command_line.h"
+#include "base/win/windows_version.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/win/hwnd_message_handler.h"
+
+#if defined(OS_WIN)
+#include "ui/base/win/shell.h"
+#endif
+
+namespace views {
+
+namespace {
+
+void CalculateWindowStylesFromInitParams(
+ const Widget::InitParams& params,
+ WidgetDelegate* widget_delegate,
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DWORD* style,
+ DWORD* ex_style,
+ DWORD* class_style) {
+ *style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ *ex_style = 0;
+ *class_style = CS_DBLCLKS;
+
+ // Set type-independent style attributes.
+ if (params.child)
+ *style |= WS_CHILD;
+ if (params.show_state == ui::SHOW_STATE_MAXIMIZED)
+ *style |= WS_MAXIMIZE;
+ if (params.show_state == ui::SHOW_STATE_MINIMIZED)
+ *style |= WS_MINIMIZE;
+ if (!params.accept_events)
+ *ex_style |= WS_EX_TRANSPARENT;
+ if (!params.can_activate)
+ *ex_style |= WS_EX_NOACTIVATE;
+ if (params.keep_on_top)
+ *ex_style |= WS_EX_TOPMOST;
+ if (params.mirror_origin_in_rtl)
+ *ex_style |= l10n_util::GetExtendedTooltipStyles();
+ // Layered windows do not work with Aura. They are basically incompatible
+ // with Direct3D surfaces. Officially, it should be impossible to achieve
+ // per-pixel alpha compositing with the desktop and 3D acceleration but it
+ // has been discovered that since Vista There is a secret handshake between
+ // user32 and the DMW. If things are set up just right DMW gets out of the
+ // way; it does not create a backbuffer and simply blends our D3D surface
+ // and the desktop background. The handshake is as follows:
+ // 1- Use D3D9Ex to create device/swapchain, etc. You need D3DFMT_A8R8G8B8.
+ // 2- The window must have WS_EX_COMPOSITED in the extended style.
+ // 3- The window must have WS_POPUP in its style.
+ // 4- The windows must not have WM_SIZEBOX, WS_THICKFRAME or WS_CAPTION in its
+ // style.
+ // 5- When the window is created but before it is presented, call
+ // DwmExtendFrameIntoClientArea passing -1 as the margins.
+ if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW) {
+#if defined(USE_AURA)
+ if (ui::win::IsAeroGlassEnabled())
+ *ex_style |= WS_EX_COMPOSITED;
+#else
+ *ex_style |= WS_EX_LAYERED;
+#endif
+ }
+ if (params.has_dropshadow) {
+ *class_style |= (base::win::GetVersion() < base::win::VERSION_XP) ?
+ 0 : CS_DROPSHADOW;
+ }
+
+ // Set type-dependent style attributes.
+ switch (params.type) {
+ case Widget::InitParams::TYPE_PANEL:
+ *ex_style |= WS_EX_TOPMOST;
+ if (params.remove_standard_frame) {
+ *style |= WS_POPUP;
+ break;
+ }
+ // Else, no break. Fall through to TYPE_WINDOW.
+ case Widget::InitParams::TYPE_WINDOW: {
+ *style |= WS_SYSMENU | WS_CAPTION;
+ bool can_resize = widget_delegate->CanResize();
+ bool can_maximize = widget_delegate->CanMaximize();
+ if (can_maximize) {
+ *style |= WS_OVERLAPPEDWINDOW;
+ } else if (can_resize || params.remove_standard_frame) {
+ *style |= WS_OVERLAPPED | WS_THICKFRAME;
+ }
+ if (native_widget_delegate->IsDialogBox()) {
+ *style |= DS_MODALFRAME;
+ // NOTE: Turning this off means we lose the close button, which is bad.
+ // Turning it on though means the user can maximize or size the window
+ // from the system menu, which is worse. We may need to provide our own
+ // menu to get the close button to appear properly.
+ // style &= ~WS_SYSMENU;
+
+ // Set the WS_POPUP style for modal dialogs. This ensures that the owner
+ // window is activated on destruction. This style should not be set for
+ // non-modal non-top-level dialogs like constrained windows.
+ *style |= native_widget_delegate->IsModal() ? WS_POPUP : 0;
+ }
+ *ex_style |=
+ native_widget_delegate->IsDialogBox() ? WS_EX_DLGMODALFRAME : 0;
+
+ // See layered window comment above.
+ if (*ex_style & WS_EX_COMPOSITED)
+ *style &= ~(WS_THICKFRAME | WS_CAPTION);
+ break;
+ }
+ case Widget::InitParams::TYPE_CONTROL:
+ *style |= WS_VISIBLE;
+ break;
+ case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
+ *style |= WS_POPUP;
+ break;
+ case Widget::InitParams::TYPE_BUBBLE:
+ *style |= WS_POPUP;
+ *style |= WS_CLIPCHILDREN;
+ break;
+ case Widget::InitParams::TYPE_POPUP:
+ *style |= WS_POPUP;
+ *ex_style |= WS_EX_TOOLWINDOW;
+ break;
+ case Widget::InitParams::TYPE_MENU:
+ *style |= WS_POPUP;
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+} // namespace
+
+bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) {
+ return !(window_pos->flags & SWP_NOSIZE) ||
+ window_pos->flags & SWP_FRAMECHANGED;
+}
+
+void ConfigureWindowStyles(
+ HWNDMessageHandler* handler,
+ const Widget::InitParams& params,
+ WidgetDelegate* widget_delegate,
+ internal::NativeWidgetDelegate* native_widget_delegate) {
+ // Configure the HWNDMessageHandler with the appropriate
+ DWORD style = 0;
+ DWORD ex_style = 0;
+ DWORD class_style = 0;
+ CalculateWindowStylesFromInitParams(params, widget_delegate,
+ native_widget_delegate, &style, &ex_style,
+ &class_style);
+ handler->set_initial_class_style(class_style);
+ handler->set_window_style(handler->window_style() | style);
+ handler->set_window_ex_style(handler->window_ex_style() | ex_style);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.h b/chromium/ui/views/widget/widget_hwnd_utils.h
new file mode 100644
index 00000000000..2808bab0d48
--- /dev/null
+++ b/chromium/ui/views/widget/widget_hwnd_utils.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_WIDGET_HWND_UTILS_H_
+#define UI_VIEWS_WIDGET_WIDGET_HWND_UTILS_H_
+
+#include <windows.h>
+
+#include "ui/views/widget/widget.h"
+
+// Functions shared by native_widget_win.cc and desktop_root_window_host_win.cc:
+
+namespace views {
+class HWNDMessageHandler;
+class WidgetDelegate;
+namespace internal {
+class NativeWidgetDelegate;
+}
+
+// Returns true if the WINDOWPOS data provided indicates the client area of
+// the window may have changed size. This can be caused by the window being
+// resized or its frame changing.
+bool DidClientAreaSizeChange(const WINDOWPOS* window_pos);
+
+// Sets styles appropriate for |params| on |handler|.
+void ConfigureWindowStyles(
+ HWNDMessageHandler* handler,
+ const Widget::InitParams& params,
+ WidgetDelegate* widget_delegate,
+ internal::NativeWidgetDelegate* native_widget_delegate);
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_HWND_UTILS_H_
diff --git a/chromium/ui/views/widget/widget_observer.h b/chromium/ui/views/widget/widget_observer.h
new file mode 100644
index 00000000000..e156ef80c88
--- /dev/null
+++ b/chromium/ui/views/widget/widget_observer.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_WIDGET_OBSERVER_H_
+#define UI_VIEWS_WIDGET_WIDGET_OBSERVER_H_
+
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class Widget;
+
+// Observers can listen to various events on the Widgets.
+class VIEWS_EXPORT WidgetObserver {
+ public:
+ // The closing notification is sent immediately in response to (i.e. in the
+ // same call stack as) a request to close the Widget (via Close() or
+ // CloseNow()).
+ virtual void OnWidgetClosing(Widget* widget) {}
+
+ // Invoked after notification is received from the event loop that the native
+ // widget has been created.
+ virtual void OnWidgetCreated(Widget* widget) {}
+
+ // The destroying event occurs immediately before the widget is destroyed.
+ // This typically occurs asynchronously with respect the the close request, as
+ // a result of a later invocation from the event loop.
+ virtual void OnWidgetDestroying(Widget* widget) {}
+
+ // Invoked after notification is received from the event loop that the native
+ // widget has been destroyed.
+ virtual void OnWidgetDestroyed(Widget* widget) {}
+
+ virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) {}
+
+ virtual void OnWidgetActivationChanged(Widget* widget, bool active) {}
+
+ virtual void OnWidgetBoundsChanged(Widget* widget,
+ const gfx::Rect& new_bounds) {}
+
+ protected:
+ virtual ~WidgetObserver() {}
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_OBSERVER_H_
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
new file mode 100644
index 00000000000..1153538b8d8
--- /dev/null
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -0,0 +1,2116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/events/event_utils.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/test/test_views_delegate.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/native_widget_delegate.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/window/native_frame_view.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/test_cursor_client.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/views/widget/native_widget_aura.h"
+#if !defined(OS_CHROMEOS)
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#endif
+#elif defined(OS_WIN)
+#include "ui/views/widget/native_widget_win.h"
+#endif
+
+namespace views {
+namespace test {
+
+// A generic typedef to pick up relevant NativeWidget implementations.
+#if defined(USE_AURA)
+typedef NativeWidgetAura NativeWidgetPlatform;
+#elif defined(OS_WIN)
+typedef NativeWidgetWin NativeWidgetPlatform;
+#endif
+
+// A widget that assumes mouse capture always works. It won't on Aura in
+// testing, so we mock it.
+#if defined(USE_AURA)
+class NativeWidgetCapture : public NativeWidgetPlatform {
+ public:
+ explicit NativeWidgetCapture(internal::NativeWidgetDelegate* delegate)
+ : NativeWidgetPlatform(delegate),
+ mouse_capture_(false) {}
+ virtual ~NativeWidgetCapture() {}
+
+ virtual void SetCapture() OVERRIDE {
+ mouse_capture_ = true;
+ }
+ virtual void ReleaseCapture() OVERRIDE {
+ if (mouse_capture_)
+ delegate()->OnMouseCaptureLost();
+ mouse_capture_ = false;
+ }
+ virtual bool HasCapture() const OVERRIDE {
+ return mouse_capture_;
+ }
+
+ private:
+ bool mouse_capture_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetCapture);
+};
+#endif
+
+// A typedef that inserts our mock-capture NativeWidget implementation for
+// relevant platforms.
+#if defined(USE_AURA)
+typedef NativeWidgetCapture NativeWidgetPlatformForTest;
+#elif defined(OS_WIN)
+typedef NativeWidgetWin NativeWidgetPlatformForTest;
+#endif
+
+// A view that always processes all mouse events.
+class MouseView : public View {
+ public:
+ MouseView()
+ : View(),
+ entered_(0),
+ exited_(0),
+ pressed_(0) {
+ }
+ virtual ~MouseView() {}
+
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
+ pressed_++;
+ return true;
+ }
+
+ virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
+ entered_++;
+ }
+
+ virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
+ exited_++;
+ }
+
+ // Return the number of OnMouseEntered calls and reset the counter.
+ int EnteredCalls() {
+ int i = entered_;
+ entered_ = 0;
+ return i;
+ }
+
+ // Return the number of OnMouseExited calls and reset the counter.
+ int ExitedCalls() {
+ int i = exited_;
+ exited_ = 0;
+ return i;
+ }
+
+ int pressed() const { return pressed_; }
+
+ private:
+ int entered_;
+ int exited_;
+
+ int pressed_;
+
+ DISALLOW_COPY_AND_ASSIGN(MouseView);
+};
+
+// A view that keeps track of the events it receives, but consumes no events.
+class EventCountView : public View {
+ public:
+ EventCountView() {}
+ virtual ~EventCountView() {}
+
+ int GetEventCount(ui::EventType type) {
+ return event_count_[type];
+ }
+
+ void ResetCounts() {
+ event_count_.clear();
+ }
+
+ protected:
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ RecordEvent(*event);
+ }
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ RecordEvent(*event);
+ }
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
+ RecordEvent(*event);
+ }
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
+ RecordEvent(*event);
+ }
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ RecordEvent(*event);
+ }
+
+ private:
+ void RecordEvent(const ui::Event& event) {
+ ++event_count_[event.type()];
+ }
+
+ std::map<ui::EventType, int> event_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventCountView);
+};
+
+// A view that keeps track of the events it receives, and consumes all scroll
+// gesture events.
+class ScrollableEventCountView : public EventCountView {
+ public:
+ ScrollableEventCountView() {}
+ virtual ~ScrollableEventCountView() {}
+
+ private:
+ // Overridden from ui::EventHandler:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ EventCountView::OnGestureEvent(event);
+ switch (event->type()) {
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ case ui::ET_GESTURE_SCROLL_END:
+ case ui::ET_SCROLL_FLING_START:
+ event->SetHandled();
+ break;
+ default:
+ break;
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
+};
+
+// A view that does a capture on gesture-begin events.
+class GestureCaptureView : public View {
+ public:
+ GestureCaptureView() {}
+ virtual ~GestureCaptureView() {}
+
+ private:
+ // Overridden from View:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ if (event->type() == ui::ET_GESTURE_BEGIN) {
+ GetWidget()->SetCapture(this);
+ event->StopPropagation();
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(GestureCaptureView);
+};
+
+// A view that implements GetMinimumSize.
+class MinimumSizeFrameView : public NativeFrameView {
+ public:
+ explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {}
+ virtual ~MinimumSizeFrameView() {}
+
+ private:
+ // Overridden from View:
+ virtual gfx::Size GetMinimumSize() OVERRIDE {
+ return gfx::Size(300, 400);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MinimumSizeFrameView);
+};
+
+// An event handler that simply keeps a count of the different types of events
+// it receives.
+class EventCountHandler : public ui::EventHandler {
+ public:
+ EventCountHandler() {}
+ virtual ~EventCountHandler() {}
+
+ int GetEventCount(ui::EventType type) {
+ return event_count_[type];
+ }
+
+ void ResetCounts() {
+ event_count_.clear();
+ }
+
+ protected:
+ // Overridden from ui::EventHandler:
+ virtual void OnEvent(ui::Event* event) OVERRIDE {
+ RecordEvent(*event);
+ ui::EventHandler::OnEvent(event);
+ }
+
+ private:
+ void RecordEvent(const ui::Event& event) {
+ ++event_count_[event.type()];
+ }
+
+ std::map<ui::EventType, int> event_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
+};
+
+// A View that shows a different widget, sets capture on that widget, and
+// initiates a nested message-loop when it receives a mouse-press event.
+class NestedLoopCaptureView : public View {
+ public:
+ explicit NestedLoopCaptureView(Widget* widget) : widget_(widget) {}
+ virtual ~NestedLoopCaptureView() {}
+
+ private:
+ // Overridden from View:
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
+ // Start a nested loop.
+ widget_->Show();
+ widget_->SetCapture(widget_->GetContentsView());
+ EXPECT_TRUE(widget_->HasCapture());
+
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+
+ base::RunLoop run_loop;
+#if defined(USE_AURA)
+ run_loop.set_dispatcher(aura::Env::GetInstance()->GetDispatcher());
+#endif
+ run_loop.Run();
+ return true;
+ }
+
+ Widget* widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView);
+};
+
+// A View that closes the Widget and exits the current message-loop when it
+// receives a mouse-release event.
+class ExitLoopOnRelease : public View {
+ public:
+ ExitLoopOnRelease() {}
+ virtual ~ExitLoopOnRelease() {}
+
+ private:
+ // Overridden from View:
+ virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
+ GetWidget()->Close();
+ base::MessageLoop::current()->QuitNow();
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ExitLoopOnRelease);
+};
+
+class WidgetTest : public ViewsTestBase {
+ public:
+ WidgetTest() {}
+ virtual ~WidgetTest() {}
+
+ NativeWidget* CreatePlatformNativeWidget(
+ internal::NativeWidgetDelegate* delegate) {
+ return new NativeWidgetPlatformForTest(delegate);
+ }
+
+ Widget* CreateTopLevelPlatformWidget() {
+ Widget* toplevel = new Widget;
+ Widget::InitParams toplevel_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
+ toplevel->Init(toplevel_params);
+ return toplevel;
+ }
+
+ Widget* CreateTopLevelFramelessPlatformWidget() {
+ Widget* toplevel = new Widget;
+ Widget::InitParams toplevel_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
+ toplevel->Init(toplevel_params);
+ return toplevel;
+ }
+
+ Widget* CreateChildPlatformWidget(gfx::NativeView parent_native_view) {
+ Widget* child = new Widget;
+ Widget::InitParams child_params =
+ CreateParams(Widget::InitParams::TYPE_CONTROL);
+ child_params.native_widget = CreatePlatformNativeWidget(child);
+ child_params.parent = parent_native_view;
+ child->Init(child_params);
+ child->SetContentsView(new View);
+ return child;
+ }
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+ // On Windows, it is possible for us to have a child window that is
+ // TYPE_POPUP.
+ Widget* CreateChildPopupPlatformWidget(gfx::NativeView parent_native_view) {
+ Widget* child = new Widget;
+ Widget::InitParams child_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ child_params.child = true;
+ child_params.native_widget = CreatePlatformNativeWidget(child);
+ child_params.parent = parent_native_view;
+ child->Init(child_params);
+ child->SetContentsView(new View);
+ return child;
+ }
+#endif
+
+ Widget* CreateTopLevelNativeWidget() {
+ Widget* toplevel = new Widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ toplevel->Init(params);
+ return toplevel;
+ }
+
+ Widget* CreateChildNativeWidgetWithParent(Widget* parent) {
+ Widget* child = new Widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_CONTROL);
+ params.parent = parent->GetNativeView();
+ child->Init(params);
+ child->SetContentsView(new View);
+ return child;
+ }
+
+ Widget* CreateChildNativeWidget() {
+ return CreateChildNativeWidgetWithParent(NULL);
+ }
+
+ View* GetMousePressedHandler(internal::RootView* root_view) {
+ return root_view->mouse_pressed_handler_;
+ }
+
+ View* GetMouseMoveHandler(internal::RootView* root_view) {
+ return root_view->mouse_move_handler_;
+ }
+
+ View* GetGestureHandler(internal::RootView* root_view) {
+ return root_view->gesture_handler_;
+ }
+};
+
+bool WidgetHasMouseCapture(const Widget* widget) {
+ return static_cast<const internal::NativeWidgetPrivate*>(widget->
+ native_widget())->HasCapture();
+}
+
+ui::WindowShowState GetWidgetShowState(const Widget* widget) {
+ // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
+ // because the former is implemented on all platforms but the latter is not.
+ return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
+ widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
+ widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
+ ui::SHOW_STATE_NORMAL;
+}
+
+TEST_F(WidgetTest, WidgetInitParams) {
+ ASSERT_FALSE(views_delegate().UseTransparentWindows());
+
+ // Widgets are not transparent by default.
+ Widget::InitParams init1;
+ EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
+
+ // Non-window widgets are not transparent either.
+ Widget::InitParams init2(Widget::InitParams::TYPE_MENU);
+ EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init2.opacity);
+
+ // A ViewsDelegate can set windows transparent by default.
+ views_delegate().SetUseTransparentWindows(true);
+ Widget::InitParams init3;
+ EXPECT_EQ(Widget::InitParams::TRANSLUCENT_WINDOW, init3.opacity);
+
+ // Non-window widgets stay opaque.
+ Widget::InitParams init4(Widget::InitParams::TYPE_MENU);
+ EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init4.opacity);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget::GetTopLevelWidget tests.
+
+TEST_F(WidgetTest, GetTopLevelWidget_Native) {
+ // Create a hierarchy of native widgets.
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ gfx::NativeView parent = toplevel->GetNativeView();
+ Widget* child = CreateChildPlatformWidget(parent);
+
+ EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
+ EXPECT_EQ(toplevel, child->GetTopLevelWidget());
+
+ toplevel->CloseNow();
+ // |child| should be automatically destroyed with |toplevel|.
+}
+
+// Tests some grab/ungrab events.
+TEST_F(WidgetTest, DISABLED_GrabUngrab) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
+ Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
+
+ toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
+
+ child1->SetBounds(gfx::Rect(10, 10, 300, 300));
+ View* view = new MouseView();
+ view->SetBounds(0, 0, 300, 300);
+ child1->GetRootView()->AddChildView(view);
+
+ child2->SetBounds(gfx::Rect(200, 10, 200, 200));
+ view = new MouseView();
+ view->SetBounds(0, 0, 200, 200);
+ child2->GetRootView()->AddChildView(view);
+
+ toplevel->Show();
+ RunPendingMessages();
+
+ // Click on child1
+ gfx::Point p1(45, 45);
+ ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ toplevel->OnMouseEvent(&pressed);
+
+ EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
+ EXPECT_TRUE(WidgetHasMouseCapture(child1));
+ EXPECT_FALSE(WidgetHasMouseCapture(child2));
+
+ ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ toplevel->OnMouseEvent(&released);
+
+ EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
+ EXPECT_FALSE(WidgetHasMouseCapture(child1));
+ EXPECT_FALSE(WidgetHasMouseCapture(child2));
+
+ RunPendingMessages();
+
+ // Click on child2
+ gfx::Point p2(315, 45);
+ ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ toplevel->OnMouseEvent(&pressed2);
+ EXPECT_TRUE(pressed2.handled());
+ EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
+ EXPECT_TRUE(WidgetHasMouseCapture(child2));
+ EXPECT_FALSE(WidgetHasMouseCapture(child1));
+
+ ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ toplevel->OnMouseEvent(&released2);
+ EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
+ EXPECT_FALSE(WidgetHasMouseCapture(child1));
+ EXPECT_FALSE(WidgetHasMouseCapture(child2));
+
+ toplevel->CloseNow();
+}
+
+// Tests mouse move outside of the window into the "resize controller" and back
+// will still generate an OnMouseEntered and OnMouseExited event..
+TEST_F(WidgetTest, CheckResizeControllerEvents) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
+
+ MouseView* view = new MouseView();
+ view->SetBounds(90, 90, 10, 10);
+ toplevel->GetRootView()->AddChildView(view);
+
+ toplevel->Show();
+ RunPendingMessages();
+
+ // Move to an outside position.
+ gfx::Point p1(200, 200);
+ ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE);
+ toplevel->OnMouseEvent(&moved_out);
+ EXPECT_EQ(0, view->EnteredCalls());
+ EXPECT_EQ(0, view->ExitedCalls());
+
+ // Move onto the active view.
+ gfx::Point p2(95, 95);
+ ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE);
+ toplevel->OnMouseEvent(&moved_over);
+ EXPECT_EQ(1, view->EnteredCalls());
+ EXPECT_EQ(0, view->ExitedCalls());
+
+ // Move onto the outer resizing border.
+ gfx::Point p3(102, 95);
+ ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE);
+ toplevel->OnMouseEvent(&moved_resizer);
+ EXPECT_EQ(0, view->EnteredCalls());
+ EXPECT_EQ(1, view->ExitedCalls());
+
+ // Move onto the view again.
+ toplevel->OnMouseEvent(&moved_over);
+ EXPECT_EQ(1, view->EnteredCalls());
+ EXPECT_EQ(0, view->ExitedCalls());
+
+ RunPendingMessages();
+
+ toplevel->CloseNow();
+}
+
+// Test if a focus manager and an inputmethod work without CHECK failure
+// when window activation changes.
+TEST_F(WidgetTest, ChangeActivation) {
+ Widget* top1 = CreateTopLevelPlatformWidget();
+ // CreateInputMethod before activated
+ top1->GetInputMethod();
+ top1->Show();
+ RunPendingMessages();
+
+ Widget* top2 = CreateTopLevelPlatformWidget();
+ top2->Show();
+ RunPendingMessages();
+
+ top1->Activate();
+ RunPendingMessages();
+
+ // Create InputMethod after deactivated.
+ top2->GetInputMethod();
+ top2->Activate();
+ RunPendingMessages();
+
+ top1->Activate();
+ RunPendingMessages();
+
+ top1->CloseNow();
+ top2->CloseNow();
+}
+
+// Tests visibility of child widgets.
+TEST_F(WidgetTest, Visibility) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ gfx::NativeView parent = toplevel->GetNativeView();
+ Widget* child = CreateChildPlatformWidget(parent);
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child->IsVisible());
+
+ child->Show();
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child->IsVisible());
+
+ toplevel->Show();
+
+ EXPECT_TRUE(toplevel->IsVisible());
+ EXPECT_TRUE(child->IsVisible());
+
+ toplevel->CloseNow();
+ // |child| should be automatically destroyed with |toplevel|.
+}
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+// On Windows, it is possible to have child window that are TYPE_POPUP. Unlike
+// regular child windows, these should be created as hidden and must be shown
+// explicitly.
+TEST_F(WidgetTest, Visibility_ChildPopup) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ Widget* child_popup = CreateChildPopupPlatformWidget(
+ toplevel->GetNativeView());
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child_popup->IsVisible());
+
+ toplevel->Show();
+
+ EXPECT_TRUE(toplevel->IsVisible());
+ EXPECT_FALSE(child_popup->IsVisible());
+
+ child_popup->Show();
+
+ EXPECT_TRUE(child_popup->IsVisible());
+
+ toplevel->CloseNow();
+ // |child_popup| should be automatically destroyed with |toplevel|.
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget ownership tests.
+//
+// Tests various permutations of Widget ownership specified in the
+// InitParams::Ownership param.
+
+// A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
+class WidgetOwnershipTest : public WidgetTest {
+ public:
+ WidgetOwnershipTest() {}
+ virtual ~WidgetOwnershipTest() {}
+
+ virtual void SetUp() {
+ WidgetTest::SetUp();
+ desktop_widget_ = CreateTopLevelPlatformWidget();
+ }
+
+ virtual void TearDown() {
+ desktop_widget_->CloseNow();
+ WidgetTest::TearDown();
+ }
+
+ private:
+ Widget* desktop_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
+};
+
+// A bag of state to monitor destructions.
+struct OwnershipTestState {
+ OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
+
+ bool widget_deleted;
+ bool native_widget_deleted;
+};
+
+// A platform NativeWidget subclass that updates a bag of state when it is
+// destroyed.
+class OwnershipTestNativeWidget : public NativeWidgetPlatform {
+ public:
+ OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
+ OwnershipTestState* state)
+ : NativeWidgetPlatform(delegate),
+ state_(state) {
+ }
+ virtual ~OwnershipTestNativeWidget() {
+ state_->native_widget_deleted = true;
+ }
+
+ private:
+ OwnershipTestState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
+};
+
+// A views NativeWidget subclass that updates a bag of state when it is
+// destroyed.
+class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
+ public:
+ OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
+ OwnershipTestState* state)
+ : NativeWidgetPlatformForTest(delegate),
+ state_(state) {
+ }
+ virtual ~OwnershipTestNativeWidgetPlatform() {
+ state_->native_widget_deleted = true;
+ }
+
+ private:
+ OwnershipTestState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
+};
+
+// A Widget subclass that updates a bag of state when it is destroyed.
+class OwnershipTestWidget : public Widget {
+ public:
+ explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
+ virtual ~OwnershipTestWidget() {
+ state_->widget_deleted = true;
+ }
+
+ private:
+ OwnershipTestState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
+};
+
+// Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
+// widget.
+TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
+ OwnershipTestState state;
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Now delete the Widget, which should delete the NativeWidget.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+
+ // TODO(beng): write test for this ownership scenario and the NativeWidget
+ // being deleted out from under the Widget.
+}
+
+// Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
+TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
+ OwnershipTestState state;
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Now delete the Widget, which should delete the NativeWidget.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+
+ // TODO(beng): write test for this ownership scenario and the NativeWidget
+ // being deleted out from under the Widget.
+}
+
+// Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
+// destroy the parent view.
+TEST_F(WidgetOwnershipTest,
+ Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.parent = toplevel->GetNativeView();
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Now close the toplevel, which deletes the view hierarchy.
+ toplevel->CloseNow();
+
+ RunPendingMessages();
+
+ // This shouldn't delete the widget because it shouldn't be deleted
+ // from the native side.
+ EXPECT_FALSE(state.widget_deleted);
+ EXPECT_FALSE(state.native_widget_deleted);
+
+ // Now delete it explicitly.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
+// widget.
+TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
+ OwnershipTestState state;
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ widget->Init(params);
+
+ // Now destroy the native widget.
+ widget->CloseNow();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
+TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ params.parent = toplevel->GetNativeView();
+ widget->Init(params);
+
+ // Now destroy the native widget. This is achieved by closing the toplevel.
+ toplevel->CloseNow();
+
+ // The NativeWidget won't be deleted until after a return to the message loop
+ // so we have to run pending messages before testing the destruction status.
+ RunPendingMessages();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
+// widget, destroyed out from under it by the OS.
+TEST_F(WidgetOwnershipTest,
+ Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
+ OwnershipTestState state;
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ widget->Init(params);
+
+ // Now simulate a destroy of the platform native widget from the OS:
+#if defined(USE_AURA)
+ delete widget->GetNativeView();
+#elif defined(OS_WIN)
+ DestroyWindow(widget->GetNativeView());
+#endif
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
+// destroyed by the view hierarchy that contains it.
+TEST_F(WidgetOwnershipTest,
+ Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ params.parent = toplevel->GetNativeView();
+ widget->Init(params);
+
+ // Destroy the widget (achieved by closing the toplevel).
+ toplevel->CloseNow();
+
+ // The NativeWidget won't be deleted until after a return to the message loop
+ // so we have to run pending messages before testing the destruction status.
+ RunPendingMessages();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
+// we close it directly.
+TEST_F(WidgetOwnershipTest,
+ Ownership_ViewsNativeWidgetOwnsWidget_Close) {
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ params.parent = toplevel->GetNativeView();
+ widget->Init(params);
+
+ // Destroy the widget.
+ widget->Close();
+ toplevel->CloseNow();
+
+ // The NativeWidget won't be deleted until after a return to the message loop
+ // so we have to run pending messages before testing the destruction status.
+ RunPendingMessages();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
+TEST_F(WidgetOwnershipTest,
+ Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
+ OwnershipTestState state;
+
+ WidgetDelegateView* delegate_view = new WidgetDelegateView;
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.delegate = delegate_view;
+ widget->Init(params);
+ widget->SetContentsView(delegate_view);
+
+ // Now delete the Widget. There should be no crash or use-after-free.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget observer tests.
+//
+
+class WidgetObserverTest : public WidgetTest, public WidgetObserver {
+ public:
+ WidgetObserverTest()
+ : active_(NULL),
+ widget_closed_(NULL),
+ widget_activated_(NULL),
+ widget_shown_(NULL),
+ widget_hidden_(NULL),
+ widget_bounds_changed_(NULL) {
+ }
+
+ virtual ~WidgetObserverTest() {}
+
+ // Overridden from WidgetObserver:
+ virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
+ if (active_ == widget)
+ active_ = NULL;
+ widget_closed_ = widget;
+ }
+
+ virtual void OnWidgetActivationChanged(Widget* widget,
+ bool active) OVERRIDE {
+ if (active) {
+ if (widget_activated_)
+ widget_activated_->Deactivate();
+ widget_activated_ = widget;
+ active_ = widget;
+ } else {
+ if (widget_activated_ == widget)
+ widget_activated_ = NULL;
+ widget_deactivated_ = widget;
+ }
+ }
+
+ virtual void OnWidgetVisibilityChanged(Widget* widget,
+ bool visible) OVERRIDE {
+ if (visible)
+ widget_shown_ = widget;
+ else
+ widget_hidden_ = widget;
+ }
+
+ virtual void OnWidgetBoundsChanged(Widget* widget,
+ const gfx::Rect& new_bounds) OVERRIDE {
+ widget_bounds_changed_ = widget;
+ }
+
+ void reset() {
+ active_ = NULL;
+ widget_closed_ = NULL;
+ widget_activated_ = NULL;
+ widget_deactivated_ = NULL;
+ widget_shown_ = NULL;
+ widget_hidden_ = NULL;
+ widget_bounds_changed_ = NULL;
+ }
+
+ Widget* NewWidget() {
+ Widget* widget = CreateTopLevelNativeWidget();
+ widget->AddObserver(this);
+ return widget;
+ }
+
+ const Widget* active() const { return active_; }
+ const Widget* widget_closed() const { return widget_closed_; }
+ const Widget* widget_activated() const { return widget_activated_; }
+ const Widget* widget_deactivated() const { return widget_deactivated_; }
+ const Widget* widget_shown() const { return widget_shown_; }
+ const Widget* widget_hidden() const { return widget_hidden_; }
+ const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
+
+ private:
+ Widget* active_;
+
+ Widget* widget_closed_;
+ Widget* widget_activated_;
+ Widget* widget_deactivated_;
+ Widget* widget_shown_;
+ Widget* widget_hidden_;
+ Widget* widget_bounds_changed_;
+};
+
+TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* toplevel1 = NewWidget();
+ Widget* toplevel2 = NewWidget();
+
+ toplevel1->Show();
+ toplevel2->Show();
+
+ reset();
+
+ toplevel1->Activate();
+
+ RunPendingMessages();
+ EXPECT_EQ(toplevel1, widget_activated());
+
+ toplevel2->Activate();
+ RunPendingMessages();
+ EXPECT_EQ(toplevel1, widget_deactivated());
+ EXPECT_EQ(toplevel2, widget_activated());
+ EXPECT_EQ(toplevel2, active());
+
+ toplevel->CloseNow();
+}
+
+TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* child1 = NewWidget();
+ Widget* child2 = NewWidget();
+
+ toplevel->Show();
+ child1->Show();
+ child2->Show();
+
+ reset();
+
+ child1->Hide();
+ EXPECT_EQ(child1, widget_hidden());
+
+ child2->Hide();
+ EXPECT_EQ(child2, widget_hidden());
+
+ child1->Show();
+ EXPECT_EQ(child1, widget_shown());
+
+ child2->Show();
+ EXPECT_EQ(child2, widget_shown());
+
+ toplevel->CloseNow();
+}
+
+TEST_F(WidgetObserverTest, DestroyBubble) {
+ Widget* anchor = CreateTopLevelPlatformWidget();
+ anchor->Show();
+
+ BubbleDelegateView* bubble_delegate =
+ new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE);
+ Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
+ bubble_widget->Show();
+ bubble_widget->CloseNow();
+
+ anchor->Hide();
+ anchor->CloseNow();
+}
+
+TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
+ Widget* child1 = NewWidget();
+ Widget* child2 = NewWidget();
+
+ child1->OnNativeWidgetMove();
+ EXPECT_EQ(child1, widget_bounds_changed());
+
+ child2->OnNativeWidgetMove();
+ EXPECT_EQ(child2, widget_bounds_changed());
+
+ child1->OnNativeWidgetSizeChanged(gfx::Size());
+ EXPECT_EQ(child1, widget_bounds_changed());
+
+ child2->OnNativeWidgetSizeChanged(gfx::Size());
+ EXPECT_EQ(child2, widget_bounds_changed());
+}
+
+#if !defined(USE_AURA) && defined(OS_WIN)
+// Aura needs shell to maximize/fullscreen window.
+// NativeWidgetGtk doesn't implement GetRestoredBounds.
+TEST_F(WidgetTest, GetRestoredBounds) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+ toplevel->Show();
+ toplevel->Maximize();
+ RunPendingMessages();
+ EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+ EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
+ EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
+
+ toplevel->Restore();
+ RunPendingMessages();
+ EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+
+ toplevel->SetFullscreen(true);
+ RunPendingMessages();
+ EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+ EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
+ EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
+}
+#endif
+
+// Test that window state is not changed after getting out of full screen.
+TEST_F(WidgetTest, ExitFullscreenRestoreState) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ toplevel->Show();
+ RunPendingMessages();
+
+ // This should be a normal state window.
+ EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
+
+ toplevel->SetFullscreen(true);
+ while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
+ RunPendingMessages();
+ toplevel->SetFullscreen(false);
+ while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
+ RunPendingMessages();
+
+ // And it should still be in normal state after getting out of full screen.
+ EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
+
+ // Now, make it maximized.
+ toplevel->Maximize();
+ while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_MAXIMIZED)
+ RunPendingMessages();
+
+ toplevel->SetFullscreen(true);
+ while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
+ RunPendingMessages();
+ toplevel->SetFullscreen(false);
+ while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
+ RunPendingMessages();
+
+ // And it stays maximized after getting out of full screen.
+ EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
+
+ // Clean up.
+ toplevel->Close();
+ RunPendingMessages();
+}
+
+// Checks that if a mouse-press triggers a capture on a different widget (which
+// consumes the mouse-release event), then the target of the press does not have
+// capture.
+TEST_F(WidgetTest, CaptureWidgetFromMousePress) {
+ // The test creates two widgets: |first| and |second|.
+ // The View in |first| makes |second| visible, sets capture on it, and starts
+ // a nested loop (like a menu does). The View in |second| terminates the
+ // nested loop and closes the widget.
+ // The test sends a mouse-press event to |first|, and posts a task to send a
+ // release event to |second|, to make sure that the release event is
+ // dispatched after the nested loop starts.
+
+ Widget* first = CreateTopLevelFramelessPlatformWidget();
+ Widget* second = CreateTopLevelFramelessPlatformWidget();
+
+ View* container = new NestedLoopCaptureView(second);
+ first->SetContentsView(container);
+
+ second->SetContentsView(new ExitLoopOnRelease());
+
+ first->SetSize(gfx::Size(100, 100));
+ first->Show();
+
+ gfx::Point location(20, 20);
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&Widget::OnMouseEvent,
+ base::Unretained(second),
+ base::Owned(new ui::MouseEvent(ui::ET_MOUSE_RELEASED,
+ location,
+ location,
+ ui::EF_LEFT_MOUSE_BUTTON))));
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ first->OnMouseEvent(&press);
+ EXPECT_FALSE(first->HasCapture());
+ first->Close();
+ RunPendingMessages();
+}
+
+TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
+ Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
+ View* container = new View;
+ toplevel->SetContentsView(container);
+
+ View* gesture = new GestureCaptureView;
+ gesture->SetBounds(0, 0, 30, 30);
+ container->AddChildView(gesture);
+
+ MouseView* mouse = new MouseView;
+ mouse->SetBounds(30, 0, 30, 30);
+ container->AddChildView(mouse);
+
+ toplevel->SetSize(gfx::Size(100, 100));
+ toplevel->Show();
+
+ // Start a gesture on |gesture|.
+ ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
+ 15, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
+ ui::GestureEvent end(ui::ET_GESTURE_END,
+ 15, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
+ toplevel->OnGestureEvent(&begin);
+
+ // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
+ // will not receive the event.
+ gfx::Point click_location(45, 15);
+
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
+ ui::EF_LEFT_MOUSE_BUTTON);
+
+ toplevel->OnMouseEvent(&press);
+ toplevel->OnMouseEvent(&release);
+ EXPECT_EQ(0, mouse->pressed());
+
+ // The end of the gesture should release the capture, and pressing on |mouse|
+ // should now reach |mouse|.
+ toplevel->OnGestureEvent(&end);
+ toplevel->OnMouseEvent(&press);
+ toplevel->OnMouseEvent(&release);
+ EXPECT_EQ(1, mouse->pressed());
+
+ toplevel->Close();
+ RunPendingMessages();
+}
+
+#if defined(USE_AURA)
+// The key-event propagation from Widget happens differently on aura and
+// non-aura systems because of the difference in IME. So this test works only on
+// aura.
+TEST_F(WidgetTest, KeyboardInputEvent) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ View* container = toplevel->client_view();
+
+ Textfield* textfield = new Textfield();
+ textfield->SetText(ASCIIToUTF16("some text"));
+ container->AddChildView(textfield);
+ toplevel->Show();
+ textfield->RequestFocus();
+
+ // The press gets handled. The release doesn't have an effect.
+ ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, 0, false);
+ toplevel->OnKeyEvent(&backspace_p);
+ EXPECT_TRUE(backspace_p.stopped_propagation());
+ ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, 0, false);
+ toplevel->OnKeyEvent(&backspace_r);
+ EXPECT_FALSE(backspace_r.handled());
+
+ toplevel->Close();
+}
+
+// Verifies bubbles result in a focus lost when shown.
+// TODO(msw): this tests relies on focus, it needs to be in
+// interactive_ui_tests.
+TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
+ // Create a widget, show and activate it and focus the contents view.
+ View* contents_view = new View;
+ contents_view->set_focusable(true);
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+#if !defined(OS_CHROMEOS)
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+#endif
+ widget.Init(init_params);
+ widget.SetContentsView(contents_view);
+ widget.Show();
+ widget.Activate();
+ contents_view->RequestFocus();
+ EXPECT_TRUE(contents_view->HasFocus());
+
+ // Show a bubble.
+ BubbleDelegateView* bubble_delegate_view =
+ new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
+ bubble_delegate_view->set_focusable(true);
+ BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
+ bubble_delegate_view->RequestFocus();
+
+ // |contents_view_| should no longer have focus.
+ EXPECT_FALSE(contents_view->HasFocus());
+ EXPECT_TRUE(bubble_delegate_view->HasFocus());
+
+ bubble_delegate_view->GetWidget()->CloseNow();
+
+ // Closing the bubble should result in focus going back to the contents view.
+ EXPECT_TRUE(contents_view->HasFocus());
+}
+
+// Desktop native widget Aura tests are for non Chrome OS platforms.
+#if !defined(OS_CHROMEOS)
+// Test to ensure that after minimize, view width is set to zero.
+TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
+ // Create a widget.
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.show_state = ui::SHOW_STATE_NORMAL;
+ gfx::Rect initial_bounds(0, 0, 300, 400);
+ init_params.bounds = initial_bounds;
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(init_params);
+ NonClientView* non_client_view = widget.non_client_view();
+ NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
+ non_client_view->SetFrameView(frame_view);
+ widget.Show();
+ widget.Minimize();
+ EXPECT_EQ(0, frame_view->width());
+}
+
+// This class validates whether paints are received for a visible Widget.
+// To achieve this it overrides the Show and Close methods on the Widget class
+// and sets state whether subsequent paints are expected.
+class DesktopAuraTestValidPaintWidget : public views::Widget {
+ public:
+ DesktopAuraTestValidPaintWidget()
+ : expect_paint_(true),
+ received_paint_while_hidden_(false) {
+ }
+
+ virtual ~DesktopAuraTestValidPaintWidget() {
+ }
+
+ virtual void Show() OVERRIDE {
+ expect_paint_ = true;
+ views::Widget::Show();
+ }
+
+ virtual void Close() OVERRIDE {
+ expect_paint_ = false;
+ views::Widget::Close();
+ }
+
+ void Hide() {
+ expect_paint_ = false;
+ views::Widget::Hide();
+ }
+
+ virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
+ EXPECT_TRUE(expect_paint_);
+ if (!expect_paint_)
+ received_paint_while_hidden_ = true;
+ views::Widget::OnNativeWidgetPaint(canvas);
+ }
+
+ bool received_paint_while_hidden() const {
+ return received_paint_while_hidden_;
+ }
+
+ private:
+ bool expect_paint_;
+ bool received_paint_while_hidden_;
+};
+
+TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
+ View* contents_view = new View;
+ contents_view->set_focusable(true);
+ DesktopAuraTestValidPaintWidget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(init_params);
+ widget.SetContentsView(contents_view);
+ widget.Show();
+ widget.Activate();
+ RunPendingMessages();
+ widget.SchedulePaintInRect(init_params.bounds);
+ widget.Close();
+ RunPendingMessages();
+ EXPECT_FALSE(widget.received_paint_while_hidden());
+}
+
+TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
+ View* contents_view = new View;
+ contents_view->set_focusable(true);
+ DesktopAuraTestValidPaintWidget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(init_params);
+ widget.SetContentsView(contents_view);
+ widget.Show();
+ widget.Activate();
+ RunPendingMessages();
+ widget.SchedulePaintInRect(init_params.bounds);
+ widget.Hide();
+ RunPendingMessages();
+ EXPECT_FALSE(widget.received_paint_while_hidden());
+ widget.Close();
+}
+
+// This class provides functionality to test whether the destruction of full
+// screen child windows occurs correctly in desktop AURA without crashing.
+// It provides facilities to test the following cases:-
+// 1. Child window destroyed which should lead to the destruction of the
+// parent.
+// 2. Parent window destroyed which should lead to the child being destroyed.
+class DesktopAuraFullscreenChildWindowDestructionTest
+ : public views::TestViewsDelegate,
+ public aura::WindowObserver {
+ public:
+ DesktopAuraFullscreenChildWindowDestructionTest()
+ : full_screen_widget_(NULL),
+ child_window_(NULL),
+ parent_destroyed_(false),
+ child_destroyed_(false) {}
+
+ virtual ~DesktopAuraFullscreenChildWindowDestructionTest() {
+ EXPECT_TRUE(parent_destroyed_);
+ EXPECT_TRUE(child_destroyed_);
+ full_screen_widget_ = NULL;
+ child_window_ = NULL;
+ }
+
+ // views::TestViewsDelegate overrides.
+ virtual void OnBeforeWidgetInit(
+ Widget::InitParams* params,
+ internal::NativeWidgetDelegate* delegate) OVERRIDE {
+ if (!params->native_widget)
+ params->native_widget = new views::DesktopNativeWidgetAura(delegate);
+ }
+
+ void CreateFullscreenChildWindow(const gfx::Rect& bounds) {
+ Widget::InitParams init_params;
+ init_params.type = Widget::InitParams::TYPE_WINDOW;
+ init_params.bounds = bounds;
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.layer_type = ui::LAYER_NOT_DRAWN;
+
+ widget_.Init(init_params);
+
+ child_window_ = new aura::Window(&child_window_delegate_);
+ child_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ child_window_->Init(ui::LAYER_TEXTURED);
+ child_window_->SetName("TestFullscreenChildWindow");
+ child_window_->SetProperty(aura::client::kShowStateKey,
+ ui::SHOW_STATE_FULLSCREEN);
+ child_window_->SetDefaultParentByRootWindow(
+ widget_.GetNativeView()->GetRootWindow(), gfx::Rect(0, 0, 1900, 1600));
+ child_window_->Show();
+ child_window_->AddObserver(this);
+
+ ASSERT_TRUE(child_window_->parent() != NULL);
+ child_window_->parent()->AddObserver(this);
+
+ full_screen_widget_ =
+ views::Widget::GetWidgetForNativeView(child_window_->parent());
+ ASSERT_TRUE(full_screen_widget_ != NULL);
+ }
+
+ void DestroyChildWindow() {
+ ASSERT_TRUE(child_window_ != NULL);
+ delete child_window_;
+ }
+
+ void DestroyParentWindow() {
+ ASSERT_TRUE(full_screen_widget_ != NULL);
+ full_screen_widget_->CloseNow();
+ }
+
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
+ window->RemoveObserver(this);
+ if (window == child_window_) {
+ child_destroyed_ = true;
+ } else if (window == full_screen_widget_->GetNativeView()) {
+ parent_destroyed_ = true;
+ } else {
+ ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
+ }
+ }
+
+ private:
+ views::Widget widget_;
+ views::Widget* full_screen_widget_;
+ aura::Window* child_window_;
+ bool parent_destroyed_;
+ bool child_destroyed_;
+ aura::test::TestWindowDelegate child_window_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopAuraFullscreenChildWindowDestructionTest);
+};
+
+TEST_F(WidgetTest, DesktopAuraFullscreenChildDestroyedBeforeParentTest) {
+ ViewsDelegate::views_delegate = NULL;
+ DesktopAuraFullscreenChildWindowDestructionTest full_screen_child_test;
+ ASSERT_NO_FATAL_FAILURE(full_screen_child_test.CreateFullscreenChildWindow(
+ gfx::Rect(0, 0, 200, 200)));
+
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(full_screen_child_test.DestroyChildWindow());
+ RunPendingMessages();
+}
+
+TEST_F(WidgetTest, DesktopAuraFullscreenChildParentDestroyed) {
+ ViewsDelegate::views_delegate = NULL;
+
+ DesktopAuraFullscreenChildWindowDestructionTest full_screen_child_test;
+ ASSERT_NO_FATAL_FAILURE(full_screen_child_test.CreateFullscreenChildWindow(
+ gfx::Rect(0, 0, 200, 200)));
+
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(full_screen_child_test.DestroyParentWindow());
+ RunPendingMessages();
+}
+
+// Test to ensure that the aura Window's visiblity state is set to visible if
+// the underlying widget is hidden and then shown.
+TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
+ // Create a widget.
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.show_state = ui::SHOW_STATE_NORMAL;
+ gfx::Rect initial_bounds(0, 0, 300, 400);
+ init_params.bounds = initial_bounds;
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(init_params);
+ NonClientView* non_client_view = widget.non_client_view();
+ NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
+ non_client_view->SetFrameView(frame_view);
+
+ widget.Hide();
+ EXPECT_FALSE(widget.GetNativeView()->IsVisible());
+ widget.Show();
+ EXPECT_TRUE(widget.GetNativeView()->IsVisible());
+}
+
+#endif // !defined(OS_CHROMEOS)
+
+// Tests that wheel events generated from scroll events are targetted to the
+// views under the cursor when the focused view does not processed them.
+TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
+ EventCountView* cursor_view = new EventCountView;
+ cursor_view->SetBounds(60, 0, 50, 40);
+
+ Widget* widget = CreateTopLevelPlatformWidget();
+ widget->GetRootView()->AddChildView(cursor_view);
+
+ // Generate a scroll event on the cursor view.
+ ui::ScrollEvent scroll(ui::ET_SCROLL,
+ gfx::Point(65, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&scroll);
+
+ EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
+
+ cursor_view->ResetCounts();
+
+ ui::ScrollEvent scroll2(ui::ET_SCROLL,
+ gfx::Point(5, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&scroll2);
+
+ EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
+
+ widget->CloseNow();
+}
+
+#endif // defined(USE_AURA)
+
+// Tests that if a scroll-begin gesture is not handled, then subsequent scroll
+// events are not dispatched to any view.
+TEST_F(WidgetTest, GestureScrollEventDispatching) {
+ EventCountView* noscroll_view = new EventCountView;
+ EventCountView* scroll_view = new ScrollableEventCountView;
+
+ noscroll_view->SetBounds(0, 0, 50, 40);
+ scroll_view->SetBounds(60, 0, 40, 40);
+
+ Widget* widget = CreateTopLevelPlatformWidget();
+ widget->GetRootView()->AddChildView(noscroll_view);
+ widget->GetRootView()->AddChildView(scroll_view);
+
+ {
+ ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
+ 5, 5, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
+ 1);
+ widget->OnGestureEvent(&begin);
+ ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
+ 25, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
+ 1);
+ widget->OnGestureEvent(&update);
+ ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
+ 25, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
+ 1);
+ widget->OnGestureEvent(&end);
+
+ EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
+ EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
+ }
+
+ {
+ ui::GestureEvent begin(ui::ET_GESTURE_SCROLL_BEGIN,
+ 65, 5, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
+ 1);
+ widget->OnGestureEvent(&begin);
+ ui::GestureEvent update(ui::ET_GESTURE_SCROLL_UPDATE,
+ 85, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10),
+ 1);
+ widget->OnGestureEvent(&update);
+ ui::GestureEvent end(ui::ET_GESTURE_SCROLL_END,
+ 85, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0),
+ 1);
+ widget->OnGestureEvent(&end);
+
+ EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
+ EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
+ }
+
+ widget->CloseNow();
+}
+
+// Tests that event-handlers installed on the RootView get triggered correctly.
+TEST_F(WidgetTest, EventHandlersOnRootView) {
+ Widget* widget = CreateTopLevelNativeWidget();
+ View* root_view = widget->GetRootView();
+
+ EventCountView* view = new EventCountView;
+ view->SetBounds(0, 0, 20, 20);
+ root_view->AddChildView(view);
+
+ EventCountHandler h1;
+ root_view->AddPreTargetHandler(&h1);
+
+ EventCountHandler h2;
+ root_view->AddPostTargetHandler(&h2);
+
+ widget->SetBounds(gfx::Rect(0, 0, 100, 100));
+ widget->Show();
+
+ ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
+ gfx::Point(10, 10),
+ 0, 0,
+ ui::EventTimeForNow(),
+ 1.0, 0.0, 1.0, 0.0);
+ widget->OnTouchEvent(&pressed);
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
+
+ ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
+ 5, 5, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
+ ui::GestureEvent end(ui::ET_GESTURE_END,
+ 5, 5, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
+ widget->OnGestureEvent(&begin);
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_BEGIN));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
+
+ ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
+ gfx::Point(10, 10),
+ 0, 0,
+ ui::EventTimeForNow(),
+ 1.0, 0.0, 1.0, 0.0);
+ widget->OnTouchEvent(&released);
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
+
+ widget->OnGestureEvent(&end);
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_END));
+
+ ui::ScrollEvent scroll(ui::ET_SCROLL,
+ gfx::Point(5, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&scroll);
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
+ Widget* widget = CreateTopLevelNativeWidget();
+ View* root_view = widget->GetRootView();
+
+ EventCountView* v1 = new EventCountView();
+ v1->SetBounds(0, 0, 10, 10);
+ root_view->AddChildView(v1);
+ EventCountView* v2 = new EventCountView();
+ v2->SetBounds(0, 10, 10, 10);
+ root_view->AddChildView(v2);
+
+ gfx::Point cursor_location(5, 5);
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
+ ui::EF_NONE);
+ widget->OnMouseEvent(&move);
+
+ EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+
+ delete v1;
+ v2->SetBounds(0, 0, 10, 10);
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+
+ widget->SynthesizeMouseMoveEvent();
+ EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+}
+
+TEST_F(WidgetTest, MouseEventsHandled) {
+ Widget* widget = CreateTopLevelNativeWidget();
+ View* root_view = widget->GetRootView();
+
+#if defined(USE_AURA)
+ aura::test::TestCursorClient cursor_client(
+ widget->GetNativeView()->GetRootWindow());
+#endif
+
+ EventCountView* v1 = new EventCountView();
+ v1->SetBounds(0, 0, 10, 10);
+ root_view->AddChildView(v1);
+ EventCountView* v2 = new EventCountView();
+ v2->SetBounds(0, 10, 10, 10);
+ root_view->AddChildView(v2);
+
+ gfx::Point cursor_location1(5, 5);
+ ui::MouseEvent move1(ui::ET_MOUSE_MOVED, cursor_location1, cursor_location1,
+ ui::EF_NONE);
+ widget->OnMouseEvent(&move1);
+ EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_EXITED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
+ v1->ResetCounts();
+ v2->ResetCounts();
+
+ gfx::Point cursor_location2(5, 15);
+ ui::MouseEvent move2(ui::ET_MOUSE_MOVED, cursor_location2, cursor_location2,
+ ui::EF_NONE);
+ widget->OnMouseEvent(&move2);
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_EXITED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
+ v1->ResetCounts();
+ v2->ResetCounts();
+
+#if defined(USE_AURA)
+ // In Aura, we suppress mouse events if mouse events are disabled.
+ cursor_client.DisableMouseEvents();
+
+ widget->OnMouseEvent(&move1);
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_EXITED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
+ v1->ResetCounts();
+ v2->ResetCounts();
+
+ widget->OnMouseEvent(&move2);
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_EXITED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_EXITED));
+#endif
+}
+
+// Used by SingleWindowClosing to count number of times WindowClosing() has
+// been invoked.
+class ClosingDelegate : public WidgetDelegate {
+ public:
+ ClosingDelegate() : count_(0), widget_(NULL) {}
+
+ int count() const { return count_; }
+
+ void set_widget(views::Widget* widget) { widget_ = widget; }
+
+ // WidgetDelegate overrides:
+ virtual Widget* GetWidget() OVERRIDE { return widget_; }
+ virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
+ virtual void WindowClosing() OVERRIDE {
+ count_++;
+ }
+
+ private:
+ int count_;
+ views::Widget* widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClosingDelegate);
+};
+
+// Verifies WindowClosing() is invoked correctly on the delegate when a Widget
+// is closed.
+TEST_F(WidgetTest, SingleWindowClosing) {
+ scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate());
+ Widget* widget = new Widget(); // Destroyed by CloseNow() below.
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ init_params.delegate = delegate.get();
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+ init_params.native_widget = new DesktopNativeWidgetAura(widget);
+#endif
+ widget->Init(init_params);
+ EXPECT_EQ(0, delegate->count());
+ widget->CloseNow();
+ EXPECT_EQ(1, delegate->count());
+}
+
+// Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
+class VerifyTopLevelDelegate : public TestViewsDelegate {
+ public:
+ VerifyTopLevelDelegate()
+ : on_before_init_called_(false),
+ is_top_level_(false) {
+ }
+
+ bool on_before_init_called() const { return on_before_init_called_; }
+ bool is_top_level() const { return is_top_level_; }
+
+ virtual void OnBeforeWidgetInit(
+ Widget::InitParams* params,
+ internal::NativeWidgetDelegate* delegate) OVERRIDE {
+ on_before_init_called_ = true;
+ is_top_level_ = params->top_level;
+ }
+
+ private:
+ bool on_before_init_called_;
+ bool is_top_level_;
+
+ DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
+};
+
+// Verifies |top_level| is correctly passed to
+// ViewsDelegate::OnBeforeWidgetInit().
+TEST_F(WidgetTest, SetTopLevelCorrectly) {
+ set_views_delegate(NULL);
+ VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
+ set_views_delegate(delegate); // ViewsTestBase takes ownership.
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+ EXPECT_TRUE(delegate->on_before_init_called());
+ EXPECT_TRUE(delegate->is_top_level());
+}
+
+// A scumbag View that deletes its owning widget OnMousePressed.
+class WidgetDeleterView : public View {
+ public:
+ WidgetDeleterView() : View() {}
+
+ // Overridden from View.
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
+ delete GetWidget();
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
+};
+
+TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
+ Widget* widget = new Widget;
+ Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ widget->SetContentsView(new WidgetDeleterView);
+
+ widget->SetSize(gfx::Size(100, 100));
+ widget->Show();
+
+ gfx::Point click_location(45, 15);
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ widget->OnMouseEvent(&press);
+
+ // Yay we did not crash!
+}
+
+// See description of RunGetNativeThemeFromDestructor() for details.
+class GetNativeThemeFromDestructorView : public WidgetDelegateView {
+ public:
+ GetNativeThemeFromDestructorView() {}
+ virtual ~GetNativeThemeFromDestructorView() {
+ VerifyNativeTheme();
+ }
+
+ virtual View* GetContentsView() OVERRIDE {
+ return this;
+ }
+
+ private:
+ void VerifyNativeTheme() {
+ ASSERT_TRUE(GetNativeTheme() != NULL);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(GetNativeThemeFromDestructorView);
+};
+
+// Verifies GetNativeTheme() from the destructor of a WidgetDelegateView doesn't
+// crash. |is_first_run| is true if this is the first call. A return value of
+// true indicates this should be run again with a value of false.
+// First run uses DesktopNativeWidgetAura (if possible). Second run doesn't.
+bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
+ bool is_first_run) {
+ bool needs_second_run = false;
+ // Destroyed by CloseNow() below.
+ Widget* widget = new Widget;
+ Widget::InitParams params(in_params);
+ // Deletes itself when the Widget is destroyed.
+ params.delegate = new GetNativeThemeFromDestructorView;
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+ if (is_first_run) {
+ params.native_widget = new DesktopNativeWidgetAura(widget);
+ needs_second_run = true;
+ }
+#endif
+ widget->Init(params);
+ widget->CloseNow();
+ return needs_second_run;
+}
+
+// See description of RunGetNativeThemeFromDestructor() for details.
+TEST_F(WidgetTest, GetNativeThemeFromDestructor) {
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ if (RunGetNativeThemeFromDestructor(params, true))
+ RunGetNativeThemeFromDestructor(params, false);
+}
+
+// Used by HideCloseDestroy. Allows setting a boolean when the widget is
+// destroyed.
+class CloseDestroysWidget : public Widget {
+ public:
+ explicit CloseDestroysWidget(bool* destroyed)
+ : destroyed_(destroyed) {
+ }
+
+ virtual ~CloseDestroysWidget() {
+ if (destroyed_) {
+ *destroyed_ = true;
+ base::MessageLoop::current()->QuitNow();
+ }
+ }
+
+ void Detach() { destroyed_ = NULL; }
+
+ private:
+ // If non-null set to true from destructor.
+ bool* destroyed_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
+};
+
+// Verifies Close() results in destroying.
+TEST_F(WidgetTest, CloseDestroys) {
+ bool destroyed = false;
+ CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
+ Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_MENU);
+ params.opacity = Widget::InitParams::OPAQUE_WINDOW;
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+ params.native_widget = new DesktopNativeWidgetAura(widget);
+#endif
+ widget->Init(params);
+ widget->Show();
+ widget->Hide();
+ widget->Close();
+ // Run the message loop as Close() asynchronously deletes.
+ RunPendingMessages();
+ EXPECT_TRUE(destroyed);
+ // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
+ if (!destroyed) {
+ widget->Detach();
+ widget->CloseNow();
+ }
+}
+
+// A view that consumes mouse-pressed event and gesture-tap-down events.
+class RootViewTestView : public View {
+ public:
+ RootViewTestView(): View() {}
+
+ private:
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
+ return true;
+ }
+
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ if (event->type() == ui::ET_GESTURE_TAP_DOWN)
+ event->SetHandled();
+ }
+};
+
+// Checks if RootView::*_handler_ fields are unset when widget is hidden.
+TEST_F(WidgetTest, TestRootViewHandlersWhenHidden) {
+ Widget* widget = CreateTopLevelNativeWidget();
+ widget->SetBounds(gfx::Rect(0, 0, 300, 300));
+ View* view = new RootViewTestView();
+ view->SetBounds(0, 0, 300, 300);
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget->GetRootView());
+ root_view->AddChildView(view);
+
+ // Check RootView::mouse_pressed_handler_.
+ widget->Show();
+ EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
+ gfx::Point click_location(45, 15);
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ widget->OnMouseEvent(&press);
+ EXPECT_EQ(view, GetMousePressedHandler(root_view));
+ widget->Hide();
+ EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
+
+ // Check RootView::mouse_move_handler_.
+ widget->Show();
+ EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
+ gfx::Point move_location(45, 15);
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0);
+ widget->OnMouseEvent(&move);
+ EXPECT_EQ(view, GetMouseMoveHandler(root_view));
+ widget->Hide();
+ EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
+
+ // Check RootView::gesture_handler_.
+ widget->Show();
+ EXPECT_EQ(NULL, GetGestureHandler(root_view));
+ ui::GestureEvent tap_down(
+ ui::ET_GESTURE_TAP_DOWN,
+ 15,
+ 15,
+ 0,
+ base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0),
+ 1);
+ widget->OnGestureEvent(&tap_down);
+ EXPECT_EQ(view, GetGestureHandler(root_view));
+ widget->Hide();
+ EXPECT_EQ(NULL, GetGestureHandler(root_view));
+
+ widget->Close();
+}
+
+} // namespace test
+} // namespace views
diff --git a/chromium/ui/views/widget/window_reorderer.cc b/chromium/ui/views/widget/window_reorderer.cc
new file mode 100644
index 00000000000..dcf51c83c8a
--- /dev/null
+++ b/chromium/ui/views/widget/window_reorderer.cc
@@ -0,0 +1,201 @@
+// Copyright 2013 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/views/widget/window_reorderer.h"
+
+#include <map>
+#include <vector>
+
+#include "ui/aura/window.h"
+#include "ui/views/view.h"
+#include "ui/views/view_constants_aura.h"
+
+namespace views {
+
+namespace {
+
+// Sets |hosted_windows| to a mapping of the views with an associated window to
+// the window that they are associated to. Only views associated to a child of
+// |parent_window| are returned.
+void GetViewsWithAssociatedWindow(
+ const aura::Window& parent_window,
+ std::map<views::View*, aura::Window*>* hosted_windows) {
+ const std::vector<aura::Window*>& child_windows = parent_window.children();
+ for (size_t i = 0; i < child_windows.size(); ++i) {
+ aura::Window* child = child_windows[i];
+ View* host_view = child->GetProperty(kHostViewKey);
+ if (host_view)
+ (*hosted_windows)[host_view] = child;
+ }
+}
+
+// Sets |order| to the list of views whose layer / associated window's layer
+// is a child of |parent_layer|. |order| is sorted in ascending z-order of
+// the views.
+// |hosts| are the views with an associated window whose layer is a child of
+// |parent_layer|.
+void GetOrderOfViewsWithLayers(
+ views::View* view,
+ ui::Layer* parent_layer,
+ const std::map<views::View*, aura::Window*>& hosts,
+ std::vector<views::View*>* order) {
+ DCHECK(view);
+ DCHECK(parent_layer);
+ DCHECK(order);
+ if (view->layer() && view->layer()->parent() == parent_layer) {
+ order->push_back(view);
+ // |hosts| may contain a child of |view|.
+ } else if (hosts.find(view) != hosts.end()) {
+ order->push_back(view);
+ }
+
+ for (int i = 0; i < view->child_count(); ++i)
+ GetOrderOfViewsWithLayers(view->child_at(i), parent_layer, hosts, order);
+}
+
+} // namespace
+
+// Class which reorders windows as a result of the kHostViewKey property being
+// set on the window.
+class WindowReorderer::AssociationObserver : public aura::WindowObserver {
+ public:
+ explicit AssociationObserver(WindowReorderer* reorderer);
+ virtual ~AssociationObserver();
+
+ // Start/stop observing changes in the kHostViewKey property on |window|.
+ void StartObserving(aura::Window* window);
+ void StopObserving(aura::Window* window);
+
+ private:
+ // aura::WindowObserver overrides:
+ virtual void OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ // Not owned.
+ WindowReorderer* reorderer_;
+
+ std::set<aura::Window*> windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(AssociationObserver);
+};
+
+WindowReorderer::AssociationObserver::AssociationObserver(
+ WindowReorderer* reorderer)
+ : reorderer_(reorderer) {
+}
+
+WindowReorderer::AssociationObserver::~AssociationObserver() {
+ while (!windows_.empty())
+ StopObserving(*windows_.begin());
+}
+
+void WindowReorderer::AssociationObserver::StartObserving(
+ aura::Window* window) {
+ windows_.insert(window);
+ window->AddObserver(this);
+}
+
+void WindowReorderer::AssociationObserver::StopObserving(
+ aura::Window* window) {
+ windows_.erase(window);
+ window->RemoveObserver(this);
+}
+
+void WindowReorderer::AssociationObserver::OnWindowPropertyChanged(
+ aura::Window* window,
+ const void* key,
+ intptr_t old) {
+ if (key == kHostViewKey)
+ reorderer_->ReorderChildWindows();
+}
+
+void WindowReorderer::AssociationObserver::OnWindowDestroying(
+ aura::Window* window) {
+ windows_.erase(window);
+ window->RemoveObserver(this);
+}
+
+WindowReorderer::WindowReorderer(aura::Window* parent_window,
+ View* root_view)
+ : parent_window_(parent_window),
+ root_view_(root_view),
+ association_observer_(new AssociationObserver(this)) {
+ parent_window_->AddObserver(this);
+ const std::vector<aura::Window*>& windows = parent_window_->children();
+ for (size_t i = 0; i < windows.size(); ++i)
+ association_observer_->StartObserving(windows[i]);
+ ReorderChildWindows();
+}
+
+WindowReorderer::~WindowReorderer() {
+ if (parent_window_) {
+ parent_window_->RemoveObserver(this);
+ // |association_observer_| stops observing any windows it is observing upon
+ // destruction.
+ }
+}
+
+void WindowReorderer::ReorderChildWindows() {
+ if (!parent_window_)
+ return;
+
+ std::map<View*, aura::Window*> hosted_windows;
+ GetViewsWithAssociatedWindow(*parent_window_, &hosted_windows);
+
+ if (hosted_windows.empty()) {
+ // Exit early if there are no views with associated windows.
+ // View::ReorderLayers() should have already reordered the layers owned by
+ // views.
+ return;
+ }
+
+ // Compute the desired z-order of the layers based on the order of the views
+ // with layers and views with associated windows in the view tree.
+ std::vector<View*> view_with_layer_order;
+ GetOrderOfViewsWithLayers(root_view_, parent_window_->layer(), hosted_windows,
+ &view_with_layer_order);
+
+ // For the sake of simplicity, reorder both the layers owned by views and the
+ // layers of windows associated with a view. Iterate through
+ // |view_with_layer_order| backwards and stack windows at the bottom so that
+ // windows not associated to a view are stacked above windows with an
+ // associated view.
+ for (std::vector<View*>::reverse_iterator it = view_with_layer_order.rbegin();
+ it != view_with_layer_order.rend(); ++it) {
+ View* view = *it;
+ ui::Layer* layer = view->layer();
+ aura::Window* window = NULL;
+
+ std::map<View*, aura::Window*>::iterator hosted_window_it =
+ hosted_windows.find(view);
+ if (hosted_window_it != hosted_windows.end()) {
+ window = hosted_window_it->second;
+ layer = window->layer();
+ }
+
+ DCHECK(layer);
+ if (window)
+ parent_window_->StackChildAtBottom(window);
+ parent_window_->layer()->StackAtBottom(layer);
+ }
+}
+
+void WindowReorderer::OnWindowAdded(aura::Window* new_window) {
+ association_observer_->StartObserving(new_window);
+ ReorderChildWindows();
+}
+
+void WindowReorderer::OnWillRemoveWindow(aura::Window* window) {
+ association_observer_->StopObserving(window);
+}
+
+void WindowReorderer::OnWindowDestroying(aura::Window* window) {
+ parent_window_->RemoveObserver(this);
+ parent_window_ = NULL;
+ association_observer_.reset();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/window_reorderer.h b/chromium/ui/views/widget/window_reorderer.h
new file mode 100644
index 00000000000..b04e48f8904
--- /dev/null
+++ b/chromium/ui/views/widget/window_reorderer.h
@@ -0,0 +1,59 @@
+// Copyright 2013 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_VIEWS_WIDGET_WINDOW_REORDERER_H_
+#define UI_VIEWS_WIDGET_WINDOW_REORDERER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+class View;
+
+// Class which reorders the widget's child windows which have an associated view
+// in the widget's view tree according the z-order of the views in the view
+// tree. Windows not associated to a view are stacked above windows with an
+// associated view. The child windows' layers are additionally reordered
+// according to the z-order of the associated views relative to views with
+// layers.
+class WindowReorderer : public aura::WindowObserver {
+ public:
+ WindowReorderer(aura::Window* window, View* root_view);
+ virtual ~WindowReorderer();
+
+ // Explicitly reorder the children of |window_| (and their layers). This
+ // method should be called when the position of a view with an associated
+ // window changes in the view hierarchy. This method assumes that the
+ // child layers of |window_| which are owned by views are already in the
+ // correct z-order relative to each other and does no reordering if there
+ // are no views with an associated window.
+ void ReorderChildWindows();
+
+ private:
+ // aura::WindowObserver overrides:
+ virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE;
+ virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ // The window and the root view of the native widget which owns the
+ // WindowReorderer.
+ aura::Window* parent_window_;
+ View* root_view_;
+
+ // Reorders windows as a result of the kHostViewKey being set on a child of
+ // |parent_window_|.
+ class AssociationObserver;
+ scoped_ptr<AssociationObserver> association_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowReorderer);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WINDOW_REORDERER_H_
diff --git a/chromium/ui/views/widget/window_reorderer_unittest.cc b/chromium/ui/views/widget/window_reorderer_unittest.cc
new file mode 100644
index 00000000000..1d9566c916e
--- /dev/null
+++ b/chromium/ui/views/widget/window_reorderer_unittest.cc
@@ -0,0 +1,263 @@
+// Copyright 2013 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 "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/test/test_layers.h"
+#include "ui/views/view.h"
+#include "ui/views/view_constants_aura.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace {
+
+// Creates a control widget with the passed in parameters.
+// The caller takes ownership of the returned widget.
+Widget* CreateControlWidget(aura::Window* parent, const gfx::Rect& bounds) {
+ Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = parent;
+ params.bounds = bounds;
+ Widget* widget = new Widget();
+ widget->Init(params);
+ return widget;
+}
+
+// Sets the name of |window| and |window|'s layer to |name|.
+void SetWindowAndLayerName(aura::Window* window, const std::string& name) {
+ window->SetName(name);
+ window->layer()->set_name(name);
+}
+
+// Returns a string containing the name of each of the child windows (bottommost
+// first) of |parent|. The format of the string is "name1 name2 name3 ...".
+std::string ChildWindowNamesAsString(const aura::Window& parent) {
+ std::string names;
+ typedef std::vector<aura::Window*> Windows;
+ for (Windows::const_iterator it = parent.children().begin();
+ it != parent.children().end(); ++it) {
+ if (!names.empty())
+ names += " ";
+ names += (*it)->name();
+ }
+ return names;
+}
+
+typedef aura::test::AuraTestBase WindowReordererTest;
+
+// Test that views with layers and views with associated windows are reordered
+// according to the view hierarchy.
+TEST_F(WindowReordererTest, Basic) {
+ scoped_ptr<Widget> parent(CreateControlWidget(root_window(),
+ gfx::Rect(0, 0, 100, 100)));
+ parent->Show();
+ aura::Window* parent_window = parent->GetNativeWindow();
+
+ View* contents_view = new View();
+ parent->SetContentsView(contents_view);
+
+ // 1) Test that layers for views and layers for windows associated to a host
+ // view are stacked below the layers for any windows not associated to a host
+ // view.
+ View* v = new View();
+ v->SetPaintToLayer(true);
+ v->layer()->set_name("v");
+ contents_view->AddChildView(v);
+
+ scoped_ptr<Widget> w1(CreateControlWidget(parent_window,
+ gfx::Rect(0, 1, 100, 101)));
+ SetWindowAndLayerName(w1->GetNativeView(), "w1");
+ w1->Show();
+ scoped_ptr<Widget> w2(CreateControlWidget(parent_window,
+ gfx::Rect(0, 2, 100, 102)));
+ SetWindowAndLayerName(w2->GetNativeView(), "w2");
+ w2->Show();
+
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w1 w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ View* host_view2 = new View();
+ contents_view->AddChildView(host_view2);
+ w2->GetNativeView()->SetProperty(kHostViewKey, host_view2);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ View* host_view1 = new View();
+ w1->GetNativeView()->SetProperty(kHostViewKey, host_view1);
+ contents_view->AddChildViewAt(host_view1, 0);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 v w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 2) Test the z-order of the windows and layers as a result of reordering the
+ // views.
+ contents_view->ReorderChildView(host_view1, -1);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ contents_view->ReorderChildView(host_view2, -1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w1 w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 3) Test the z-order of the windows and layers as a result of reordering the
+ // views in situations where the window order remains unchanged.
+ contents_view->ReorderChildView(v, -1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 w2 v",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ contents_view->ReorderChildView(host_view2, -1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 v w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+// Test that different orderings of:
+// - adding a window to a parent widget
+// - adding a "host" view to a parent widget
+// - associating the "host" view and window
+// all correctly reorder the child windows and layers.
+TEST_F(WindowReordererTest, Association) {
+ scoped_ptr<Widget> parent(CreateControlWidget(root_window(),
+ gfx::Rect(0, 0, 100, 100)));
+ parent->Show();
+ aura::Window* parent_window = parent->GetNativeWindow();
+
+ View* contents_view = new View();
+ parent->SetContentsView(contents_view);
+
+ aura::Window* w1 = aura::test::CreateTestWindowWithId(0,
+ parent->GetNativeWindow());
+ SetWindowAndLayerName(w1, "w1");
+
+ aura::Window* w2 = aura::test::CreateTestWindowWithId(0, NULL);
+ SetWindowAndLayerName(w2, "w2");
+
+ View* host_view2 = new View();
+
+ // 1) Test that parenting the window to the parent widget last results in a
+ // correct ordering of child windows and layers.
+ contents_view->AddChildView(host_view2);
+ w2->SetProperty(views::kHostViewKey, host_view2);
+ EXPECT_EQ("w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ parent_window->AddChild(w2);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 2) Test that associating the window and "host" view last results in a
+ // correct ordering of child windows and layers.
+ View* host_view1 = new View();
+ contents_view->AddChildViewAt(host_view1, 0);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ w1->SetProperty(views::kHostViewKey, host_view1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 3) Test that parenting the "host" view to the parent widget last results
+ // in a correct ordering of child windows and layers.
+ contents_view->RemoveChildView(host_view2);
+ contents_view->AddChildViewAt(host_view2, 0);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+// It is possible to associate a window to a view which has a parent layer
+// (other than the widget layer). In this case, the parent layer of the host
+// view and the parent layer of the associated window are different. Test that
+// the layers and windows are properly reordered in this case.
+TEST_F(WindowReordererTest, HostViewParentHasLayer) {
+ scoped_ptr<Widget> parent(CreateControlWidget(root_window(),
+ gfx::Rect(0, 0, 100, 100)));
+ parent->Show();
+ aura::Window* parent_window = parent->GetNativeWindow();
+
+ View* contents_view = new View();
+ parent->SetContentsView(contents_view);
+
+ // Create the following view hierarchy. (*) denotes views which paint to a
+ // layer.
+ //
+ // contents_view
+ // +-- v1
+ // +-- v11*
+ // +-- v12 (attached window)
+ // +-- v13*
+ // +--v2*
+
+ View* v1 = new View();
+ contents_view->AddChildView(v1);
+
+ View* v11 = new View();
+ v11->SetPaintToLayer(true);
+ v11->layer()->set_name("v11");
+ v1->AddChildView(v11);
+
+ scoped_ptr<Widget> w(CreateControlWidget(parent_window,
+ gfx::Rect(0, 1, 100, 101)));
+ SetWindowAndLayerName(w->GetNativeView(), "w");
+ w->Show();
+
+ View* v12 = new View();
+ v1->AddChildView(v12);
+ w->GetNativeView()->SetProperty(kHostViewKey, v12);
+
+ View* v13 = new View();
+ v13->SetPaintToLayer(true);
+ v13->layer()->set_name("v13");
+ v1->AddChildView(v13);
+
+ View* v2 = new View();
+ v2->SetPaintToLayer(true);
+ v2->layer()->set_name("v2");
+ contents_view->AddChildView(v2);
+
+ // Test intial state.
+ EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v11 w v13 v2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // |w|'s layer should be stacked above |v1|'s layer.
+ v1->SetPaintToLayer(true);
+ v1->layer()->set_name("v1");
+ EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v1 w v2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Test moving the host view from one view with a layer to another.
+ v2->AddChildView(v12);
+ EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v1 v2 w",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+} // namespace
+} // namespace views