summaryrefslogtreecommitdiff
path: root/chromium/ui/views/widget
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-10-13 13:24:50 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-10-14 10:57:25 +0000
commitaf3d4809763ef308f08ced947a73b624729ac7ea (patch)
tree4402b911e30383f6c6dace1e8cf3b8e85355db3a /chromium/ui/views/widget
parent0e8ff63a407fe323e215bb1a2c423c09a4747c8a (diff)
downloadqtwebengine-chromium-af3d4809763ef308f08ced947a73b624729ac7ea.tar.gz
BASELINE: Update Chromium to 47.0.2526.14
Also adding in sources needed for spellchecking. Change-Id: Idd44170fa1616f26315188970a8d5ba7d472b18a Reviewed-by: Michael BrĂ¼ning <michael.bruning@theqtcompany.com>
Diffstat (limited to 'chromium/ui/views/widget')
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc128
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc12
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc27
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc65
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc4
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h1
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h13
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm42
-rw-r--r--chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm37
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm378
-rw-r--r--chromium/ui/views/widget/widget.cc18
-rw-r--r--chromium/ui/views/widget/widget.h5
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc6
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc379
23 files changed, 746 insertions, 410 deletions
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
index 888791bd34f..8b040cae30c 100644
--- 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
@@ -242,7 +242,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
// Reprocesses the most recent mouse move event if the mouse has not moved
// in a while in case the window stacking order has changed and
// |source_current_window_| needs to be updated.
- base::OneShotTimer<DesktopDragDropClientAuraX11> repeat_mouse_move_timer_;
+ base::OneShotTimer repeat_mouse_move_timer_;
// When the mouse is released, we need to wait for the last XdndStatus message
// only if we have previously received a status message from
@@ -271,7 +271,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
// Ends the move loop if the target is too slow to respond after the mouse is
// released.
- base::OneShotTimer<DesktopDragDropClientAuraX11> end_move_loop_timer_;
+ base::OneShotTimer end_move_loop_timer_;
// Widget that the user drags around. May be NULL.
scoped_ptr<Widget> drag_widget_;
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
index 8afa69bdcbf..1549b2e45f0 100644
--- 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
@@ -5,7 +5,6 @@
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
#include "base/metrics/histogram_macros.h"
-#include "base/tracked_objects.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drag_source_win.h"
#include "ui/base/dragdrop/drop_target_event.h"
@@ -52,13 +51,9 @@ int DesktopDragDropClientWin::StartDragAndDrop(
UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Start", source,
ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
- // Use task stopwatch to exclude the drag-drop time current task, if any.
- tracked_objects::TaskStopwatch stopwatch;
- stopwatch.Start();
HRESULT result = DoDragDrop(
ui::OSExchangeDataProviderWin::GetIDataObject(data), drag_source_.Get(),
ui::DragDropTypes::DragOperationToDropEffect(operation), &effect);
- stopwatch.Stop();
drag_source_copy->set_data(nullptr);
if (alive)
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index 64f7c42cd37..b2d301d018f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -20,8 +20,13 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_delegate.h"
#include "ui/wm/public/dispatcher_client.h"
+#if defined(OS_WIN)
+#include "ui/views/win/hwnd_util.h"
+#endif
+
namespace views {
namespace test {
@@ -504,5 +509,128 @@ TEST_F(DesktopAuraWidgetTest, CloseWidgetDuringMouseReleased) {
RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
}
+// Provides functionality to create a window modal dialog.
+class ModalDialogDelegate : public DialogDelegateView {
+ public:
+ ModalDialogDelegate() {}
+ ~ModalDialogDelegate() override {}
+
+ // WidgetDelegate overrides.
+ ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
+};
+
+// This test verifies that whether mouse events when a modal dialog is
+// displayed are eaten or recieved by the dialog.
+TEST_F(WidgetTest, WindowMouseModalityTest) {
+ // Create a top level widget.
+ Widget top_level_widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.show_state = ui::SHOW_STATE_NORMAL;
+ gfx::Rect initial_bounds(0, 0, 500, 500);
+ init_params.bounds = initial_bounds;
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget =
+ new PlatformDesktopNativeWidget(&top_level_widget);
+ top_level_widget.Init(init_params);
+ top_level_widget.Show();
+ EXPECT_TRUE(top_level_widget.IsVisible());
+
+ // Create a view and validate that a mouse moves makes it to the view.
+ EventCountView* widget_view = new EventCountView();
+ widget_view->SetBounds(0, 0, 10, 10);
+ top_level_widget.GetRootView()->AddChildView(widget_view);
+
+ gfx::Point cursor_location_main(5, 5);
+ ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, cursor_location_main,
+ cursor_location_main, ui::EventTimeForNow(),
+ ui::EF_NONE, ui::EF_NONE);
+ ui::EventDispatchDetails details =
+ GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+
+ EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
+ widget_view->ResetCounts();
+
+ // Create a modal dialog and validate that a mouse down message makes it to
+ // the main view within the dialog.
+
+ // This instance will be destroyed when the dialog is destroyed.
+ ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
+
+ Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
+ dialog_delegate, NULL, top_level_widget.GetNativeView());
+ modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
+ EventCountView* dialog_widget_view = new EventCountView();
+ dialog_widget_view->SetBounds(0, 0, 50, 50);
+ modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
+ modal_dialog_widget->Show();
+ EXPECT_TRUE(modal_dialog_widget->IsVisible());
+
+ gfx::Point cursor_location_dialog(100, 100);
+ ui::MouseEvent mouse_down_dialog(
+ ui::ET_MOUSE_PRESSED, cursor_location_dialog, cursor_location_dialog,
+ ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+ details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
+ &mouse_down_dialog);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
+
+ // Send a mouse move message to the main window. It should not be received by
+ // the main window as the modal dialog is still active.
+ gfx::Point cursor_location_main2(6, 6);
+ ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, cursor_location_main2,
+ cursor_location_main2, ui::EventTimeForNow(),
+ ui::EF_NONE, ui::EF_NONE);
+ details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
+ &mouse_down_main);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
+
+ modal_dialog_widget->CloseNow();
+ top_level_widget.CloseNow();
+}
+
+#if defined(OS_WIN)
+// Tests whether we can activate the top level widget when a modal dialog is
+// active.
+TEST_F(WidgetTest, WindowModalityActivationTest) {
+ TestDesktopWidgetDelegate widget_delegate;
+ widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
+
+ Widget* top_level_widget = widget_delegate.GetWidget();
+ top_level_widget->Show();
+ EXPECT_TRUE(top_level_widget->IsVisible());
+
+ HWND win32_window = views::HWNDForWidget(top_level_widget);
+ EXPECT_TRUE(::IsWindow(win32_window));
+
+ // This instance will be destroyed when the dialog is destroyed.
+ ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
+
+ // We should be able to activate the window even if the WidgetDelegate
+ // says no, when a modal dialog is active.
+ widget_delegate.set_can_activate(false);
+
+ Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
+ dialog_delegate, NULL, top_level_widget->GetNativeView());
+ modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
+ modal_dialog_widget->Show();
+ EXPECT_TRUE(modal_dialog_widget->IsVisible());
+
+ LRESULT activate_result = ::SendMessage(
+ win32_window,
+ WM_MOUSEACTIVATE,
+ reinterpret_cast<WPARAM>(win32_window),
+ MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
+ EXPECT_EQ(activate_result, MA_ACTIVATE);
+
+ modal_dialog_widget->CloseNow();
+}
+#endif // defined(OS_WIN)
+
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index fc477e61d5d..827f294f4d0 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -184,11 +184,10 @@ gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
}
gfx::Display DesktopScreenX11::GetDisplayNearestPoint(
- const gfx::Point& requested_point) const {
- const gfx::Point point_in_pixel = DIPToPixelPoint(requested_point);
+ const gfx::Point& point) const {
for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
it != displays_.end(); ++it) {
- if (it->bounds().Contains(point_in_pixel))
+ if (it->bounds().Contains(point))
return *it;
}
@@ -239,7 +238,7 @@ uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) {
if (configure_timer_.get() && configure_timer_->IsRunning()) {
configure_timer_->Reset();
} else {
- configure_timer_.reset(new base::OneShotTimer<DesktopScreenX11>());
+ configure_timer_.reset(new base::OneShotTimer());
configure_timer_->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
@@ -326,9 +325,8 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
gfx::ToFlooredPoint(
gfx::ScalePoint(intersection_in_pixels.origin(),
1.0f / display.device_scale_factor())),
- gfx::ToFlooredSize(
- gfx::ScaleSize(intersection_in_pixels.size(),
- 1.0f / display.device_scale_factor()))));
+ gfx::ScaleToFlooredSize(intersection_in_pixels.size(),
+ 1.0f / display.device_scale_factor())));
}
switch (crtc->rotation) {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
index 0f9149796e6..4466ba48e91 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -75,7 +75,7 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen,
// The timer to delay configuring outputs. See also the comments in
// Dispatch().
- scoped_ptr<base::OneShotTimer<DesktopScreenX11> > configure_timer_;
+ scoped_ptr<base::OneShotTimer> configure_timer_;
gfx::DisplayChangeNotifier change_notifier_;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
index 83bf7d90dc5..466bb79d393 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
@@ -205,6 +205,8 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) {
gfx::Rect(640, 0, 1024, 768)));
NotifyDisplaysChanged(displays);
+ EXPECT_EQ(kFirstDisplay,
+ screen()->GetDisplayNearestPoint(gfx::Point(630, 10)).id());
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(650, 10)).id());
EXPECT_EQ(kFirstDisplay,
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 9278c2968c9..48368f962f2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -140,12 +140,13 @@ void DesktopWindowTreeHostWin::Init(aura::Window* content_window,
gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds);
message_handler_->Init(parent_hwnd, pixel_bounds);
- if (params.type == Widget::InitParams::TYPE_MENU) {
+ if (params.force_software_compositing) {
::SetProp(GetAcceleratedWidget(),
kForceSoftwareCompositor,
reinterpret_cast<HANDLE>(true));
}
- CreateCompositor(GetAcceleratedWidget());
+ CreateCompositor();
+ OnAcceleratedWidgetAvailable();
}
void DesktopWindowTreeHostWin::OnNativeWidgetCreated(
@@ -804,15 +805,8 @@ bool DesktopWindowTreeHostWin::HandleMouseEvent(const ui::MouseEvent& event) {
return event.handled();
}
-bool DesktopWindowTreeHostWin::HandleKeyEvent(const ui::KeyEvent& event) {
- return false;
-}
-
-bool DesktopWindowTreeHostWin::HandleUntranslatedKeyEvent(
- const ui::KeyEvent& event) {
- ui::KeyEvent duplicate_event(event);
- SendEventToProcessor(&duplicate_event);
- return duplicate_event.handled();
+void DesktopWindowTreeHostWin::HandleKeyEvent(ui::KeyEvent* event) {
+ GetInputMethod()->DispatchKeyEvent(event);
}
void DesktopWindowTreeHostWin::HandleTouchEvent(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index 047498f81b6..363c0193819 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -170,8 +170,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void HandleNativeFocus(HWND last_focused_window) override;
void HandleNativeBlur(HWND focused_window) override;
bool HandleMouseEvent(const ui::MouseEvent& event) override;
- bool HandleKeyEvent(const ui::KeyEvent& event) override;
- bool HandleUntranslatedKeyEvent(const ui::KeyEvent& event) override;
+ void HandleKeyEvent(ui::KeyEvent* event) override;
void HandleTouchEvent(const ui::TouchEvent& event) override;
bool HandleIMEMessage(UINT message,
WPARAM w_param,
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index a56deb7fc9f..ed0cb1d6f98 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -23,6 +23,7 @@
#include "ui/aura/window_property.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
#include "ui/base/hit_test.h"
+#include "ui/base/ime/input_method.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/events/devices/x11/device_list_cache_x11.h"
@@ -975,16 +976,17 @@ void DesktopWindowTreeHostX11::SetBounds(
unsigned value_mask = 0;
if (size_changed) {
+ // Update the minimum and maximum sizes in case they have changed.
+ UpdateMinAndMaxSize();
+
if (bounds_in_pixels.width() < min_size_in_pixels_.width() ||
bounds_in_pixels.height() < min_size_in_pixels_.height() ||
(!max_size_in_pixels_.IsEmpty() &&
(bounds_in_pixels.width() > max_size_in_pixels_.width() ||
bounds_in_pixels.height() > max_size_in_pixels_.height()))) {
- // Update the minimum and maximum sizes in case they have changed.
- UpdateMinAndMaxSize();
-
gfx::Size size_in_pixels = bounds_in_pixels.size();
- size_in_pixels.SetToMin(max_size_in_pixels_);
+ if (!max_size_in_pixels_.IsEmpty())
+ size_in_pixels.SetToMin(max_size_in_pixels_);
size_in_pixels.SetToMax(min_size_in_pixels_);
bounds_in_pixels.set_size(size_in_pixels);
}
@@ -1274,7 +1276,8 @@ void DesktopWindowTreeHostX11::InitX11Window(
if (window_icon) {
SetWindowIcons(gfx::ImageSkia(), *window_icon);
}
- CreateCompositor(GetAcceleratedWidget());
+ CreateCompositor();
+ OnAcceleratedWidgetAvailable();
}
gfx::Size DesktopWindowTreeHostX11::AdjustSize(
@@ -1517,6 +1520,10 @@ void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
}
}
+void DesktopWindowTreeHostX11::DispatchKeyEvent(ui::KeyEvent* event) {
+ GetInputMethod()->DispatchKeyEvent(event);
+}
+
void DesktopWindowTreeHostX11::ConvertEventToDifferentHost(
ui::LocatedEvent* located_event,
DesktopWindowTreeHostX11* host) {
@@ -1745,7 +1752,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
}
case KeyPress: {
ui::KeyEvent keydown_event(xev);
- SendEventToProcessor(&keydown_event);
+ DispatchKeyEvent(&keydown_event);
break;
}
case KeyRelease: {
@@ -1756,7 +1763,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
break;
ui::KeyEvent key_event(xev);
- SendEventToProcessor(&key_event);
+ DispatchKeyEvent(&key_event);
break;
}
case ButtonPress:
@@ -1881,7 +1888,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
case ui::ET_KEY_PRESSED:
case ui::ET_KEY_RELEASED: {
ui::KeyEvent key_event(xev);
- SendEventToProcessor(&key_event);
+ DispatchKeyEvent(&key_event);
break;
}
case ui::ET_UNKNOWN:
@@ -2021,14 +2028,14 @@ gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInPixels() const {
gfx::Rect DesktopWindowTreeHostX11::ToDIPRect(
const gfx::Rect& rect_in_pixels) const {
- gfx::RectF rect_in_dip = rect_in_pixels;
+ gfx::RectF rect_in_dip = gfx::RectF(rect_in_pixels);
GetRootTransform().TransformRectReverse(&rect_in_dip);
return gfx::ToEnclosingRect(rect_in_dip);
}
gfx::Rect DesktopWindowTreeHostX11::ToPixelRect(
const gfx::Rect& rect_in_dip) const {
- gfx::RectF rect_in_pixels = rect_in_dip;
+ gfx::RectF rect_in_pixels = gfx::RectF(rect_in_dip);
GetRootTransform().TransformRect(&rect_in_pixels);
return gfx::ToEnclosingRect(rect_in_pixels);
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index 787372d9c26..73e9e3e6fa7 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -209,6 +209,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// and dispatched to that host instead.
void DispatchTouchEvent(ui::TouchEvent* event);
+ // Dispatches a key event.
+ void DispatchKeyEvent(ui::KeyEvent* event);
+
// Updates the location of |located_event| to be in |host|'s coordinate system
// so that it can be dispatched to |host|.
void ConvertEventToDifferentHost(ui::LocatedEvent* located_event,
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
index 3d066539b63..0a947b830f2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
@@ -23,7 +23,7 @@
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/x/x11_atom_cache.h"
-#include "ui/gl/gl_surface.h"
+#include "ui/gl/test/gl_surface_test_support.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/x11_property_change_waiter.h"
@@ -126,7 +126,7 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase {
~DesktopWindowTreeHostX11Test() override {}
static void SetUpTestCase() {
- gfx::GLSurface::InitializeOneOffForTests();
+ gfx::GLSurfaceTestSupport::InitializeOneOff();
ui::RegisterPathProvider();
base::FilePath ui_test_pak_path;
ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index e821b128610..3215f3a4efe 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -23,6 +23,7 @@
#include "ui/base/x/x11_util.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/events/test/platform_event_source_test_api.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/path.h"
@@ -486,6 +487,48 @@ TEST_F(DesktopWindowTreeHostX11Test, ChildWindowDestructionDuringTearDown) {
EXPECT_TRUE(DesktopWindowTreeHostX11::GetAllOpenWindows().empty());
}
+// A Widget that allows setting the min/max size for the widget.
+class CustomSizeWidget : public Widget {
+ public:
+ CustomSizeWidget() {}
+ ~CustomSizeWidget() override {}
+
+ void set_min_size(const gfx::Size& size) { min_size_ = size; }
+ void set_max_size(const gfx::Size& size) { max_size_ = size; }
+
+ // Widget:
+ gfx::Size GetMinimumSize() const override { return min_size_; }
+ gfx::Size GetMaximumSize() const override { return max_size_; }
+
+ private:
+ gfx::Size min_size_;
+ gfx::Size max_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomSizeWidget);
+};
+
+TEST_F(DesktopWindowTreeHostX11Test, SetBoundsWithMinMax) {
+ CustomSizeWidget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(&widget);
+ params.bounds = gfx::Rect(200, 100);
+ widget.Init(params);
+ widget.Show();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ EXPECT_EQ(gfx::Size(200, 100).ToString(),
+ widget.GetWindowBoundsInScreen().size().ToString());
+ widget.SetBounds(gfx::Rect(300, 200));
+ EXPECT_EQ(gfx::Size(300, 200).ToString(),
+ widget.GetWindowBoundsInScreen().size().ToString());
+
+ widget.set_min_size(gfx::Size(100, 100));
+ widget.SetBounds(gfx::Rect(50, 500));
+ EXPECT_EQ(gfx::Size(100, 500).ToString(),
+ widget.GetWindowBoundsInScreen().size().ToString());
+}
+
class MouseEventRecorder : public ui::EventHandler {
public:
MouseEventRecorder() {}
@@ -508,25 +551,11 @@ class MouseEventRecorder : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(MouseEventRecorder);
};
-// A custom event-source that can be used to directly dispatch synthetic X11
-// events.
-class CustomX11EventSource : public ui::X11EventSource {
- public:
- CustomX11EventSource() : X11EventSource(gfx::GetXDisplay()) {}
- ~CustomX11EventSource() override {}
-
- void DispatchSingleEvent(XEvent* xevent) {
- PlatformEventSource::DispatchEvent(xevent);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CustomX11EventSource);
-};
-
class DesktopWindowTreeHostX11HighDPITest
: public DesktopWindowTreeHostX11Test {
public:
- DesktopWindowTreeHostX11HighDPITest() {}
+ DesktopWindowTreeHostX11HighDPITest()
+ : event_source_(ui::PlatformEventSource::GetInstance()) {}
~DesktopWindowTreeHostX11HighDPITest() override {}
void DispatchSingleEventToWidget(XEvent* event, Widget* widget) {
@@ -535,7 +564,7 @@ class DesktopWindowTreeHostX11HighDPITest
static_cast<XIDeviceEvent*>(event->xcookie.data);
device_event->event =
widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- event_source_.DispatchSingleEvent(event);
+ event_source_.Dispatch(event);
}
void PretendCapture(views::Widget* capture_widget) {
@@ -560,7 +589,7 @@ class DesktopWindowTreeHostX11HighDPITest
DesktopWindowTreeHostX11Test::SetUp();
}
- CustomX11EventSource event_source_;
+ ui::test::PlatformEventSourceTestAPI event_source_;
DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11HighDPITest);
};
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
index f0acc70c389..48072e8d67c 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
@@ -17,7 +17,9 @@
#include "ui/gfx/x/x11_types.h"
#include "ui/views/views_export.h"
+namespace base {
template <typename T> struct DefaultSingletonTraits;
+}
namespace views {
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
index 05bd690c6de..d7453258a56 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -26,7 +26,7 @@
#include "ui/gfx/path.h"
#include "ui/gfx/path_x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
-#include "ui/gl/gl_surface.h"
+#include "ui/gl/test/gl_surface_test_support.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/x11_property_change_waiter.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -194,7 +194,7 @@ class X11TopmostWindowFinderTest : public ViewsTestBase {
}
static void SetUpTestCase() {
- gfx::GLSurface::InitializeOneOffForTests();
+ gfx::GLSurfaceTestSupport::InitializeOneOff();
ui::RegisterPathProvider();
base::FilePath ui_test_pak_path;
ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
index 2e1db2e77e9..abe3a8a3d6f 100644
--- a/chromium/ui/views/widget/native_widget_aura.h
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -5,7 +5,6 @@
#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/focus_change_observer.h"
#include "ui/aura/window_delegate.h"
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
index b050a4be2a0..b2ed6325c54 100644
--- a/chromium/ui/views/widget/native_widget_mac.h
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -8,6 +8,12 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/native_widget_private.h"
+#if defined(__OBJC__)
+@class NativeWidgetMacNSWindow;
+#else
+class NativeWidgetMacNSWindow;
+#endif
+
namespace views {
namespace test {
class HitTestNativeWidgetMac;
@@ -36,6 +42,10 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// override this method for an early hook into the native window teardown.
virtual void OnWindowWillClose();
+ // Returns the vertical position that sheets should be anchored, in pixels
+ // from the bottom of the window.
+ virtual int SheetPositionY();
+
// internal::NativeWidgetPrivate:
void InitNativeWidget(const Widget::InitParams& params) override;
NonClientFrameView* CreateNonClientFrameView() override;
@@ -125,7 +135,8 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
protected:
// Creates the NSWindow that will be passed to the BridgedNativeWidget.
// Called by InitNativeWidget. The return value will be autoreleased.
- virtual gfx::NativeWindow CreateNSWindow(const Widget::InitParams& params);
+ virtual NativeWidgetMacNSWindow* CreateNSWindow(
+ const Widget::InitParams& params);
internal::NativeWidgetDelegate* delegate() { return delegate_; }
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index 63465a81b46..1b5b2eb12bc 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -38,6 +38,13 @@ namespace views {
namespace {
NSInteger StyleMaskForParams(const Widget::InitParams& params) {
+ // If the Widget is modal, it will be displayed as a sheet. This works best if
+ // it has NSTitledWindowMask. For example, with NSBorderlessWindowMask, the
+ // parent window still accepts input.
+ if (params.delegate &&
+ params.delegate->GetModalType() == ui::MODAL_TYPE_WINDOW)
+ return NSTitledWindowMask;
+
// TODO(tapted): Determine better masks when there are use cases for it.
if (params.remove_standard_frame)
return NSBorderlessWindowMask;
@@ -86,15 +93,24 @@ bool NativeWidgetMac::IsWindowModalSheet() const {
}
void NativeWidgetMac::OnWindowWillClose() {
- delegate_->OnNativeWidgetDestroying();
// Note: If closed via CloseNow(), |bridge_| will already be reset. If closed
- // by the user, or via Close() and a RunLoop, this will reset it.
- bridge_.reset();
+ // by the user, or via Close() and a RunLoop, notify observers while |bridge_|
+ // is still a valid pointer, then reset it.
+ if (bridge_) {
+ delegate_->OnNativeWidgetDestroying();
+ bridge_.reset();
+ }
delegate_->OnNativeWidgetDestroyed();
if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
delete this;
}
+int NativeWidgetMac::SheetPositionY() {
+ NSView* view = GetNativeView();
+ return
+ [view convertPoint:NSMakePoint(0, NSHeight([view frame])) toView:nil].y;
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetMac, internal::NativeWidgetPrivate implementation:
@@ -337,6 +353,11 @@ void NativeWidgetMac::Close() {
}
void NativeWidgetMac::CloseNow() {
+ if (!bridge_)
+ return;
+
+ // Notify observers while |bridged_| is still valid.
+ delegate_->OnNativeWidgetDestroying();
// Reset |bridge_| to NULL before destroying it.
scoped_ptr<BridgedNativeWidget> bridge(bridge_.Pass());
}
@@ -500,8 +521,7 @@ void NativeWidgetMac::ClearNativeFocus() {
}
gfx::Rect NativeWidgetMac::GetWorkAreaBoundsInScreen() const {
- NOTIMPLEMENTED();
- return gfx::Rect();
+ return gfx::ScreenRectFromNSRect([[GetNativeWindow() screen] visibleFrame]);
}
Widget::MoveLoopResult NativeWidgetMac::RunMoveLoop(
@@ -555,7 +575,8 @@ void NativeWidgetMac::RepostNativeEvent(gfx::NativeEvent native_event) {
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetMac, protected:
-NSWindow* NativeWidgetMac::CreateNSWindow(const Widget::InitParams& params) {
+NativeWidgetMacNSWindow* NativeWidgetMac::CreateNSWindow(
+ const Widget::InitParams& params) {
return [[[NativeWidgetMacNSWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:StyleMaskForParams(params)
@@ -650,7 +671,14 @@ void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
// static
void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
gfx::NativeView new_parent) {
- NOTIMPLEMENTED();
+ BridgedNativeWidget* bridge =
+ NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
+ if (bridge && bridge->parent() &&
+ bridge->parent()->GetNSWindow() == [new_parent window])
+ return; // Nothing to do.
+
+ // Not supported. See http://crbug.com/514920.
+ NOTREACHED();
}
// static
diff --git a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
index 8596c000eb2..08bdde3deff 100644
--- a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
@@ -6,6 +6,8 @@
#import <Cocoa/Cocoa.h>
+#import "base/mac/scoped_nsobject.h"
+#import "ui/base/test/windowed_nsnotification_observer.h"
#include "ui/views/test/test_widget_observer.h"
#include "ui/views/test/widget_test.h"
@@ -94,38 +96,39 @@ TEST_P(NativeWidgetMacInteractiveUITest, ShowAttainsKeyStatus) {
EXPECT_EQ(2, activationCount_);
}
-// Test that ShowInactive does not take keyWindow status from an active window.
+// Test that ShowInactive does not take keyWindow status.
TEST_P(NativeWidgetMacInteractiveUITest, ShowInactiveIgnoresKeyStatus) {
Widget* widget = MakeWidget();
- // In an application with only a single window, that window is always "active"
- // for the application unless that window is not visible. However, it will not
- // be key.
+ base::scoped_nsobject<WindowedNSNotificationObserver> waiter(
+ [[WindowedNSNotificationObserver alloc]
+ initForNotification:NSWindowDidBecomeKeyNotification
+ object:widget->GetNativeWindow()]);
+
+ EXPECT_FALSE(widget->IsVisible());
+ EXPECT_FALSE([widget->GetNativeWindow() isVisible]);
EXPECT_FALSE(widget->IsActive());
- widget->ShowInactive();
- EXPECT_TRUE(widget->IsActive());
- RunPendingMessages();
EXPECT_FALSE([widget->GetNativeWindow() isKeyWindow]);
-
- // Creating a second widget should now keep that widget active.
- Widget* widget2 = MakeWidget();
- widget2->Show();
widget->ShowInactive();
+ EXPECT_TRUE(widget->IsVisible());
+ EXPECT_TRUE([widget->GetNativeWindow() isVisible]);
EXPECT_FALSE(widget->IsActive());
- EXPECT_TRUE(widget2->IsActive());
+ EXPECT_FALSE([widget->GetNativeWindow() isKeyWindow]);
+
+ // If the window were to become active, this would activate it.
RunPendingMessages();
+ EXPECT_FALSE(widget->IsActive());
EXPECT_FALSE([widget->GetNativeWindow() isKeyWindow]);
- EXPECT_TRUE([widget2->GetNativeWindow() isKeyWindow]);
+ EXPECT_EQ(0, [waiter notificationCount]);
- // And finally activating the inactive widget should activate it and make it
- // key.
+ // Activating the inactive widget should make it key, asynchronously.
widget->Activate();
+ [waiter wait];
+ EXPECT_EQ(1, [waiter notificationCount]);
EXPECT_TRUE(widget->IsActive());
- RunPendingMessages();
EXPECT_TRUE([widget->GetNativeWindow() isKeyWindow]);
- widget2->CloseNow();
widget->CloseNow();
}
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index 2f0104c38b3..0ff4fbf20e9 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -6,6 +6,7 @@
#import <Cocoa/Cocoa.h>
+#import "base/mac/foundation_util.h"
#import "base/mac/scoped_nsobject.h"
#import "base/mac/scoped_objc_class_swizzler.h"
#include "base/run_loop.h"
@@ -13,11 +14,15 @@
#include "base/strings/sys_string_conversions.h"
#include "base/test/test_timeouts.h"
#import "testing/gtest_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
+#import "ui/base/cocoa/window_size_constants.h"
#import "ui/events/test/cocoa_test_event_utils.h"
#include "ui/events/test/event_generator.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views/cocoa/native_widget_mac_nswindow.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/native_cursor.h"
@@ -39,9 +44,68 @@
- (BOOL)_isTitleHidden;
@end
+// Test NSWindow that provides hooks via method overrides to verify behavior.
+@interface NativeWidgetMacTestWindow : NativeWidgetMacNSWindow {
+ @private
+ int invalidateShadowCount_;
+}
+@property(readonly, nonatomic) int invalidateShadowCount;
+@end
+
namespace views {
namespace test {
+// BridgedNativeWidget friend to access private members.
+class BridgedNativeWidgetTestApi {
+ public:
+ explicit BridgedNativeWidgetTestApi(NSWindow* window) {
+ bridge_ = NativeWidgetMac::GetBridgeForNativeWindow(window);
+ }
+
+ // Simulate a frame swap from the compositor. Assumes scale factor of 1.0f.
+ void SimulateFrameSwap(const gfx::Size& size) {
+ const float kScaleFactor = 1.0f;
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(size.width(), size.height());
+ SkCanvas canvas(bitmap);
+ bridge_->compositor_widget_->GotSoftwareFrame(kScaleFactor, &canvas);
+ std::vector<ui::LatencyInfo> latency_info;
+ bridge_->AcceleratedWidgetSwapCompleted(latency_info);
+ }
+
+ private:
+ BridgedNativeWidget* bridge_;
+
+ DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTestApi);
+};
+
+// Custom native_widget to create a NativeWidgetMacTestWindow.
+class TestWindowNativeWidgetMac : public NativeWidgetMac {
+ public:
+ explicit TestWindowNativeWidgetMac(Widget* delegate)
+ : NativeWidgetMac(delegate) {}
+
+ protected:
+ // NativeWidgetMac:
+ NativeWidgetMacNSWindow* CreateNSWindow(
+ const Widget::InitParams& params) override {
+ NSUInteger style_mask = NSBorderlessWindowMask;
+ if (params.type == Widget::InitParams::TYPE_WINDOW) {
+ style_mask = NSTexturedBackgroundWindowMask | NSTitledWindowMask |
+ NSClosableWindowMask | NSMiniaturizableWindowMask |
+ NSResizableWindowMask;
+ }
+ return [[[NativeWidgetMacTestWindow alloc]
+ initWithContentRect:ui::kWindowSizeDeterminedLater
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO] autorelease];
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestWindowNativeWidgetMac);
+};
+
// Tests for parts of NativeWidgetMac not covered by BridgedNativeWidget, which
// need access to Cocoa APIs.
class NativeWidgetMacTest : public WidgetTest {
@@ -51,18 +115,36 @@ class NativeWidgetMacTest : public WidgetTest {
// The content size of NSWindows made by MakeNativeParent().
NSRect ParentRect() const { return NSMakeRect(100, 100, 300, 200); }
- // Make a native NSWindow to use as a parent.
- NSWindow* MakeNativeParent() {
- native_parent_.reset(
- [[NSWindow alloc] initWithContentRect:ParentRect()
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
+ // Make a native NSWindow with the given |style_mask| to use as a parent.
+ NSWindow* MakeNativeParentWithStyle(int style_mask) {
+ native_parent_.reset([[NSWindow alloc]
+ initWithContentRect:ParentRect()
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
[native_parent_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
[native_parent_ makeKeyAndOrderFront:nil];
return native_parent_;
}
+ // Make a borderless, native NSWindow to use as a parent.
+ NSWindow* MakeNativeParent() {
+ return MakeNativeParentWithStyle(NSBorderlessWindowMask);
+ }
+
+ // Create a Widget backed by the NativeWidgetMacTestWindow NSWindow subclass.
+ Widget* CreateWidgetWithTestWindow(Widget::InitParams params,
+ NativeWidgetMacTestWindow** window) {
+ Widget* widget = new Widget;
+ params.native_widget = new TestWindowNativeWidgetMac(widget);
+ widget->Init(params);
+ widget->Show();
+ *window = base::mac::ObjCCastStrict<NativeWidgetMacTestWindow>(
+ widget->GetNativeWindow());
+ EXPECT_TRUE(*window);
+ return widget;
+ }
+
private:
base::scoped_nsobject<NSWindow> native_parent_;
@@ -71,10 +153,22 @@ class NativeWidgetMacTest : public WidgetTest {
class WidgetChangeObserver : public TestWidgetObserver {
public:
- WidgetChangeObserver(Widget* widget)
- : TestWidgetObserver(widget),
- gained_visible_count_(0),
- lost_visible_count_(0) {}
+ WidgetChangeObserver(Widget* widget) : TestWidgetObserver(widget) {}
+
+ void WaitForVisibleCounts(int gained, int lost) {
+ if (gained_visible_count_ >= gained && lost_visible_count_ >= lost)
+ return;
+
+ target_gained_visible_count_ = gained;
+ target_lost_visible_count_ = lost;
+
+ base::RunLoop run_loop;
+ run_loop_ = &run_loop;
+ base::MessageLoop::current()->task_runner()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout());
+ run_loop.Run();
+ run_loop_ = nullptr;
+ }
int gained_visible_count() const { return gained_visible_count_; }
int lost_visible_count() const { return lost_visible_count_; }
@@ -84,10 +178,16 @@ class WidgetChangeObserver : public TestWidgetObserver {
void OnWidgetVisibilityChanged(Widget* widget,
bool visible) override {
++(visible ? gained_visible_count_ : lost_visible_count_);
+ if (run_loop_ && gained_visible_count_ >= target_gained_visible_count_ &&
+ lost_visible_count_ >= target_lost_visible_count_)
+ run_loop_->Quit();
}
- int gained_visible_count_;
- int lost_visible_count_;
+ int gained_visible_count_ = 0;
+ int lost_visible_count_ = 0;
+ int target_gained_visible_count_ = 0;
+ int target_lost_visible_count_ = 0;
+ base::RunLoop* run_loop_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(WidgetChangeObserver);
};
@@ -140,16 +240,16 @@ TEST_F(NativeWidgetMacTest, HideAndShowExternally) {
[NSApp hide:nil];
// When the activation policy is NSApplicationActivationPolicyRegular, the
// calls via NSApp are asynchronous, and the run loop needs to be flushed.
- // With NSApplicationActivationPolicyProhibited, the following RunUntilIdle
- // calls are superfluous, but don't hurt.
- base::RunLoop().RunUntilIdle();
+ // With NSApplicationActivationPolicyProhibited, the following
+ // WaitForVisibleCounts calls are superfluous, but don't hurt.
+ observer.WaitForVisibleCounts(3, 3);
EXPECT_FALSE(widget->IsVisible());
EXPECT_FALSE([ns_window isVisible]);
EXPECT_EQ(3, observer.gained_visible_count());
EXPECT_EQ(3, observer.lost_visible_count());
[NSApp unhideWithoutActivation];
- base::RunLoop().RunUntilIdle();
+ observer.WaitForVisibleCounts(4, 3);
EXPECT_TRUE(widget->IsVisible());
EXPECT_TRUE([ns_window isVisible]);
EXPECT_EQ(4, observer.gained_visible_count());
@@ -157,10 +257,10 @@ TEST_F(NativeWidgetMacTest, HideAndShowExternally) {
// Hide again to test unhiding with an activation.
[NSApp hide:nil];
- base::RunLoop().RunUntilIdle();
+ observer.WaitForVisibleCounts(4, 4);
EXPECT_EQ(4, observer.lost_visible_count());
[NSApp unhide:nil];
- base::RunLoop().RunUntilIdle();
+ observer.WaitForVisibleCounts(5, 4);
EXPECT_EQ(5, observer.gained_visible_count());
// Hide again to test makeKeyAndOrderFront:.
@@ -185,20 +285,33 @@ TEST_F(NativeWidgetMacTest, HideAndShowExternally) {
// A view that counts calls to OnPaint().
class PaintCountView : public View {
public:
- PaintCountView() : paint_count_(0) {
- SetBounds(0, 0, 100, 100);
- }
+ PaintCountView() { SetBounds(0, 0, 100, 100); }
// View:
void OnPaint(gfx::Canvas* canvas) override {
EXPECT_TRUE(GetWidget()->IsVisible());
++paint_count_;
+ if (run_loop_ && paint_count_ == target_paint_count_)
+ run_loop_->Quit();
+ }
+
+ void WaitForPaintCount(int target) {
+ if (paint_count_ == target)
+ return;
+
+ target_paint_count_ = target;
+ base::RunLoop run_loop;
+ run_loop_ = &run_loop;
+ run_loop.Run();
+ run_loop_ = nullptr;
}
int paint_count() { return paint_count_; }
private:
- int paint_count_;
+ int paint_count_ = 0;
+ int target_paint_count_ = 0;
+ base::RunLoop* run_loop_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(PaintCountView);
};
@@ -208,9 +321,6 @@ class PaintCountView : public View {
TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
Widget* widget = new Widget;
Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW);
- // Make the layer not drawn, so that calls to paint can be observed
- // synchronously.
- init_params.layer_type = ui::LAYER_NOT_DRAWN;
widget->Init(init_params);
PaintCountView* view = new PaintCountView();
@@ -223,6 +333,7 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
EXPECT_TRUE(view->IsDrawn());
EXPECT_EQ(0, view->paint_count());
widget->Show();
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, observer.gained_visible_count());
EXPECT_EQ(0, observer.lost_visible_count());
@@ -232,12 +343,13 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
EXPECT_TRUE(widget->IsVisible());
// Showing should paint.
- EXPECT_EQ(1, view->paint_count());
+ view->WaitForPaintCount(1);
// First try performMiniaturize:, which requires a minimize button. Note that
// Cocoa just blocks the UI thread during the animation, so no need to do
// anything fancy to wait for it finish.
[ns_window performMiniaturize:nil];
+ base::RunLoop().RunUntilIdle();
EXPECT_TRUE(widget->IsMinimized());
EXPECT_FALSE(widget->IsVisible()); // Minimizing also makes things invisible.
@@ -252,6 +364,7 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
EXPECT_EQ(1, view->paint_count());
[ns_window deminiaturize:nil];
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(widget->IsMinimized());
EXPECT_TRUE(widget->IsVisible());
@@ -259,10 +372,11 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
EXPECT_EQ(1, observer.lost_visible_count());
EXPECT_EQ(restored_bounds, widget->GetRestoredBounds());
- EXPECT_EQ(2, view->paint_count()); // A single paint when deminiaturizing.
+ view->WaitForPaintCount(2); // A single paint when deminiaturizing.
EXPECT_FALSE([ns_window isMiniaturized]);
widget->Minimize();
+ base::RunLoop().RunUntilIdle();
EXPECT_TRUE(widget->IsMinimized());
EXPECT_TRUE([ns_window isMiniaturized]);
@@ -272,15 +386,17 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
EXPECT_EQ(2, view->paint_count()); // No paint when miniaturizing.
widget->Restore(); // If miniaturized, should deminiaturize.
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(widget->IsMinimized());
EXPECT_FALSE([ns_window isMiniaturized]);
EXPECT_EQ(3, observer.gained_visible_count());
EXPECT_EQ(2, observer.lost_visible_count());
EXPECT_EQ(restored_bounds, widget->GetRestoredBounds());
- EXPECT_EQ(3, view->paint_count());
+ view->WaitForPaintCount(3);
widget->Restore(); // If not miniaturized, does nothing.
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(widget->IsMinimized());
EXPECT_FALSE([ns_window isMiniaturized]);
@@ -547,16 +663,19 @@ TEST_F(NativeWidgetMacTest, Tooltips) {
namespace {
-// Delegate to make Widgets of MODAL_TYPE_CHILD.
-class ChildModalDialogDelegate : public DialogDelegateView {
+// Delegate to make Widgets of a provided ui::ModalType.
+class ModalDialogDelegate : public DialogDelegateView {
public:
- ChildModalDialogDelegate() {}
+ explicit ModalDialogDelegate(ui::ModalType modal_type)
+ : modal_type_(modal_type) {}
// WidgetDelegate:
- ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_CHILD; }
+ ui::ModalType GetModalType() const override { return modal_type_; }
private:
- DISALLOW_COPY_AND_ASSIGN(ChildModalDialogDelegate);
+ const ui::ModalType modal_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
};
// While in scope, waits for a call to a swizzled objective C method, then quits
@@ -616,7 +735,8 @@ ScopedSwizzleWaiter* ScopedSwizzleWaiter::instance_ = nullptr;
// animation). However, testing with overlapping swizzlers is tricky.
Widget* ShowChildModalWidgetAndWait(NSWindow* native_parent) {
Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
- new ChildModalDialogDelegate, nullptr, [native_parent contentView]);
+ new ModalDialogDelegate(ui::MODAL_TYPE_CHILD), nullptr,
+ [native_parent contentView]);
modal_dialog_widget->SetBounds(gfx::Rect(50, 50, 200, 150));
EXPECT_FALSE(modal_dialog_widget->IsVisible());
@@ -688,6 +808,118 @@ TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) {
}
}
+// Tests behavior of window-modal dialogs, displayed as sheets.
+TEST_F(NativeWidgetMacTest, WindowModalSheet) {
+ NSWindow* native_parent =
+ MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
+
+ Widget* sheet_widget = views::DialogDelegate::CreateDialogWidget(
+ new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW), nullptr,
+ [native_parent contentView]);
+
+ // Retain, to run checks after the Widget is torn down.
+ base::scoped_nsobject<NSWindow> sheet_window(
+ [sheet_widget->GetNativeWindow() retain]);
+
+ // Although there is no titlebar displayed, sheets need NSTitledWindowMask in
+ // order to properly engage window-modal behavior in AppKit.
+ EXPECT_EQ(NSTitledWindowMask, [sheet_window styleMask]);
+
+ sheet_widget->SetBounds(gfx::Rect(50, 50, 200, 150));
+ EXPECT_FALSE(sheet_widget->IsVisible());
+ EXPECT_FALSE(sheet_widget->GetLayer()->IsDrawn());
+
+ NSButton* parent_close_button =
+ [native_parent standardWindowButton:NSWindowCloseButton];
+ EXPECT_TRUE(parent_close_button);
+ EXPECT_TRUE([parent_close_button isEnabled]);
+
+ bool did_observe = false;
+ bool* did_observe_ptr = &did_observe;
+ id observer = [[NSNotificationCenter defaultCenter]
+ addObserverForName:NSWindowWillBeginSheetNotification
+ object:native_parent
+ queue:nil
+ usingBlock:^(NSNotification* note) {
+ // Ensure that before the sheet runs, the window contents would
+ // be drawn.
+ EXPECT_TRUE(sheet_widget->IsVisible());
+ EXPECT_TRUE(sheet_widget->GetLayer()->IsDrawn());
+ *did_observe_ptr = true;
+ }];
+
+ sheet_widget->Show(); // Should run the above block, then animate the sheet.
+ EXPECT_TRUE(did_observe);
+ [[NSNotificationCenter defaultCenter] removeObserver:observer];
+
+ // Modal, so the close button in the parent window should get disabled.
+ EXPECT_FALSE([parent_close_button isEnabled]);
+
+ // Trigger the close. Don't use CloseNow, since that tears down the UI before
+ // the close sheet animation gets a chance to run (so it's banned).
+ sheet_widget->Close();
+ EXPECT_TRUE(sheet_widget->IsVisible());
+
+ did_observe = false;
+
+ // Experimentally (on 10.10), this notification is posted from within the
+ // -[NSWindow orderOut:] call that is triggered from -[ViewsNSWindowDelegate
+ // sheetDidEnd:]. |sheet_widget| will be destroyed next, so it's still safe to
+ // use in the block. However, since the orderOut just happened, it's not very
+ // interesting.
+ observer = [[NSNotificationCenter defaultCenter]
+ addObserverForName:NSWindowDidEndSheetNotification
+ object:native_parent
+ queue:nil
+ usingBlock:^(NSNotification* note) {
+ EXPECT_TRUE([sheet_window delegate]);
+ EXPECT_FALSE(sheet_widget->IsVisible());
+ EXPECT_FALSE(sheet_widget->GetLayer()->IsDrawn());
+ *did_observe_ptr = true;
+ }];
+
+ // Pump in order to trigger -[NSWindow endSheet:..], which will block while
+ // the animation runs, then delete |sheet_widget|.
+ TestWidgetObserver widget_observer(sheet_widget);
+ EXPECT_TRUE([sheet_window delegate]);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE([sheet_window delegate]);
+
+ EXPECT_TRUE(did_observe); // Also ensures the Close() actually uses sheets.
+ [[NSNotificationCenter defaultCenter] removeObserver:observer];
+
+ EXPECT_TRUE(widget_observer.widget_closed());
+ EXPECT_TRUE([parent_close_button isEnabled]);
+}
+
+// Test calls to Widget::ReparentNativeView() that result in a no-op on Mac.
+// Tests with both native and non-native parents.
+TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
+ NSWindow* parent = MakeNativeParent();
+ Widget* dialog = views::DialogDelegate::CreateDialogWidget(
+ new DialogDelegateView, nullptr, [parent contentView]);
+ BridgedNativeWidget* bridge =
+ NativeWidgetMac::GetBridgeForNativeWindow(dialog->GetNativeWindow());
+
+ EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+ Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
+ EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+
+ [parent close];
+
+ Widget* parent_widget = CreateNativeDesktopWidget();
+ parent = parent_widget->GetNativeWindow();
+ dialog = views::DialogDelegate::CreateDialogWidget(
+ new DialogDelegateView, nullptr, [parent contentView]);
+ bridge = NativeWidgetMac::GetBridgeForNativeWindow(dialog->GetNativeWindow());
+
+ EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+ Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
+ EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+
+ parent_widget->CloseNow();
+}
+
// Tests Cocoa properties that should be given to particular widget types.
TEST_F(NativeWidgetMacTest, NativeProperties) {
// Create a regular widget (TYPE_WINDOW).
@@ -702,7 +934,8 @@ TEST_F(NativeWidgetMacTest, NativeProperties) {
// Create a dialog widget (also TYPE_WINDOW), but with a DialogDelegate.
Widget* dialog_widget = views::DialogDelegate::CreateDialogWidget(
- new ChildModalDialogDelegate, nullptr, regular_widget->GetNativeView());
+ new ModalDialogDelegate(ui::MODAL_TYPE_CHILD), nullptr,
+ regular_widget->GetNativeView());
EXPECT_TRUE([dialog_widget->GetNativeWindow() canBecomeKeyWindow]);
// Dialogs shouldn't take main status away from their parent.
EXPECT_FALSE([dialog_widget->GetNativeWindow() canBecomeMainWindow]);
@@ -796,6 +1029,68 @@ TEST_F(NativeWidgetMacTest, DoesHideTitle) {
widget->CloseNow();
}
+// Test calls to invalidate the shadow when composited frames arrive.
+TEST_F(NativeWidgetMacTest, InvalidateShadow) {
+ NativeWidgetMacTestWindow* window;
+ const gfx::Rect rect(0, 0, 100, 200);
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.bounds = rect;
+ Widget* widget = CreateWidgetWithTestWindow(init_params, &window);
+
+ // Simulate the initial paint.
+ BridgedNativeWidgetTestApi(window).SimulateFrameSwap(rect.size());
+
+ // Default is an opaque window, so shadow doesn't need to be invalidated.
+ EXPECT_EQ(0, [window invalidateShadowCount]);
+ widget->CloseNow();
+
+ init_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
+ widget = CreateWidgetWithTestWindow(init_params, &window);
+ BridgedNativeWidgetTestApi test_api(window);
+
+ // First paint on a translucent window needs to invalidate the shadow. Once.
+ EXPECT_EQ(0, [window invalidateShadowCount]);
+ test_api.SimulateFrameSwap(rect.size());
+ EXPECT_EQ(1, [window invalidateShadowCount]);
+ test_api.SimulateFrameSwap(rect.size());
+ EXPECT_EQ(1, [window invalidateShadowCount]);
+
+ // Resizing the window also needs to trigger a shadow invalidation.
+ [window setContentSize:NSMakeSize(123, 456)];
+ // A "late" frame swap at the old size should do nothing.
+ test_api.SimulateFrameSwap(rect.size());
+ EXPECT_EQ(1, [window invalidateShadowCount]);
+
+ test_api.SimulateFrameSwap(gfx::Size(123, 456));
+ EXPECT_EQ(2, [window invalidateShadowCount]);
+ test_api.SimulateFrameSwap(gfx::Size(123, 456));
+ EXPECT_EQ(2, [window invalidateShadowCount]);
+
+ widget->CloseNow();
+}
+
+// Test the expected result of GetWorkAreaBoundsInScreen().
+TEST_F(NativeWidgetMacTest, GetWorkAreaBoundsInScreen) {
+ Widget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+
+ // This is relative to the top-left of the primary screen, so unless the bot's
+ // display is smaller than 400x300, the window will be wholly contained there.
+ params.bounds = gfx::Rect(100, 100, 300, 200);
+ widget.Init(params);
+ widget.Show();
+ NSRect expected = [[[NSScreen screens] objectAtIndex:0] visibleFrame];
+ NSRect actual = gfx::ScreenRectToNSRect(widget.GetWorkAreaBoundsInScreen());
+ EXPECT_FALSE(NSIsEmptyRect(actual));
+ EXPECT_NSEQ(expected, actual);
+
+ [widget.GetNativeWindow() close];
+ actual = gfx::ScreenRectToNSRect(widget.GetWorkAreaBoundsInScreen());
+ EXPECT_TRUE(NSIsEmptyRect(actual));
+}
+
} // namespace test
} // namespace views
@@ -804,3 +1099,14 @@ TEST_F(NativeWidgetMacTest, DoesHideTitle) {
views::test::ScopedSwizzleWaiter::GetMethodAndMarkCalled()(self, _cmd);
}
@end
+
+@implementation NativeWidgetMacTestWindow
+
+@synthesize invalidateShadowCount = invalidateShadowCount_;
+
+- (void)invalidateShadow {
+ ++invalidateShadowCount_;
+ [super invalidateShadow];
+}
+
+@end
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index 280969a84e5..e1fc508d798 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -21,6 +21,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/event_monitor.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/focus_manager_factory.h"
#include "ui/views/focus/view_storage.h"
@@ -122,7 +123,8 @@ Widget::InitParams::InitParams()
desktop_window_tree_host(NULL),
layer_type(ui::LAYER_TEXTURED),
context(NULL),
- force_show_in_taskbar(false) {
+ force_show_in_taskbar(false),
+ force_software_compositing(false) {
}
Widget::InitParams::InitParams(Type type)
@@ -145,7 +147,8 @@ Widget::InitParams::InitParams(Type type)
desktop_window_tree_host(NULL),
layer_type(ui::LAYER_TEXTURED),
context(NULL),
- force_show_in_taskbar(false) {
+ force_show_in_taskbar(false),
+ force_software_compositing(false) {
}
Widget::InitParams::~InitParams() {
@@ -988,9 +991,16 @@ gfx::Rect Widget::GetWorkAreaBoundsInScreen() const {
}
void Widget::SynthesizeMouseMoveEvent() {
+ // In screen coordinate.
+ gfx::Point mouse_location = EventMonitor::GetLastMouseLocation();
+ if (!GetWindowBoundsInScreen().Contains(mouse_location))
+ return;
+
+ // Convert: screen coordinate -> widget coordinate.
+ View::ConvertPointFromScreen(root_view_.get(), &mouse_location);
last_mouse_event_was_move_ = false;
- ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, last_mouse_event_position_,
- last_mouse_event_position_, ui::EventTimeForNow(),
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, mouse_location,
+ mouse_location, ui::EventTimeForNow(),
ui::EF_IS_SYNTHESIZED, 0);
root_view_->OnMouseMoved(mouse_event);
}
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index 320332bec24..301c0aff1a1 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -9,7 +9,6 @@
#include <stack>
#include <vector>
-#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observer.h"
@@ -266,6 +265,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
std::string wm_role_name;
std::string wm_class_name;
std::string wm_class_class;
+
+ // If true then the widget uses software compositing. Defaults to false.
+ // Only used on Windows.
+ bool force_software_compositing;
};
Widget();
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 4b5a01d754e..e1e0e49a071 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -18,7 +18,7 @@
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gl/gl_surface.h"
+#include "ui/gl/test/gl_surface_test_support.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/focus/focus_manager.h"
@@ -274,7 +274,7 @@ class WidgetTestInteractive : public WidgetTest {
~WidgetTestInteractive() override {}
void SetUp() override {
- gfx::GLSurface::InitializeOneOffForTests();
+ gfx::GLSurfaceTestSupport::InitializeOneOff();
ui::RegisterPathProvider();
base::FilePath ui_test_pak_path;
ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
@@ -1142,7 +1142,7 @@ class WidgetCaptureTest : public ViewsTestBase {
~WidgetCaptureTest() override {}
void SetUp() override {
- gfx::GLSurface::InitializeOneOffForTests();
+ gfx::GLSurfaceTestSupport::InitializeOneOff();
ui::RegisterPathProvider();
base::FilePath ui_test_pak_path;
ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index ba0c03b2342..b6a18a94f67 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -41,6 +41,7 @@
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
+#include "ui/base/test/scoped_fake_nswindow_fullscreen.h"
#endif
namespace views {
@@ -68,68 +69,6 @@ bool IsTestingSnowLeopard() {
} // namespace
-// A view that keeps track of the events it receives, optionally consuming them.
-class EventCountView : public View {
- public:
- // Whether to call SetHandled() on events as they are received. For some event
- // types, this will allow EventCountView to receives future events in the
- // event sequence, such as a drag.
- enum HandleMode {
- PROPAGATE_EVENTS,
- CONSUME_EVENTS
- };
-
- EventCountView()
- : last_flags_(0),
- handle_mode_(PROPAGATE_EVENTS) {}
-
- ~EventCountView() override {}
-
- int GetEventCount(ui::EventType type) {
- return event_count_[type];
- }
-
- void ResetCounts() {
- event_count_.clear();
- }
-
- int last_flags() const {
- return last_flags_;
- }
-
- void set_handle_mode(HandleMode handle_mode) {
- handle_mode_ = handle_mode;
- }
-
- protected:
- // Overridden from View:
- void OnMouseMoved(const ui::MouseEvent& event) override {
- // MouseMove events are not re-dispatched from the RootView.
- ++event_count_[ui::ET_MOUSE_MOVED];
- last_flags_ = 0;
- }
-
- // Overridden from ui::EventHandler:
- void OnKeyEvent(ui::KeyEvent* event) override { RecordEvent(event); }
- void OnMouseEvent(ui::MouseEvent* event) override { RecordEvent(event); }
- void OnScrollEvent(ui::ScrollEvent* event) override { RecordEvent(event); }
- void OnGestureEvent(ui::GestureEvent* event) override { RecordEvent(event); }
-
- private:
- void RecordEvent(ui::Event* event) {
- ++event_count_[event->type()];
- last_flags_ = event->flags();
- if (handle_mode_ == CONSUME_EVENTS)
- event->SetHandled();
- }
-
- std::map<ui::EventType, int> event_count_;
- int last_flags_;
- HandleMode handle_mode_;
-
- DISALLOW_COPY_AND_ASSIGN(EventCountView);
-};
-
// A view that keeps track of the events it receives, and consumes all scroll
// gesture events and ui::ET_SCROLL events.
class ScrollableEventCountView : public EventCountView {
@@ -207,67 +146,6 @@ class EventCountHandler : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
};
-// A helper WidgetDelegate for tests that require hooks into WidgetDelegate
-// calls, and removes some of the boilerplate for initializing a Widget. Calls
-// Widget::CloseNow() when destroyed if it hasn't already been done.
-class TestDesktopWidgetDelegate : public WidgetDelegate {
- public:
- TestDesktopWidgetDelegate() : widget_(new Widget) {}
-
- ~TestDesktopWidgetDelegate() override {
- if (widget_)
- widget_->CloseNow();
- EXPECT_FALSE(widget_);
- }
-
- // Initialize the Widget, adding some meaningful default InitParams.
- void InitWidget(Widget::InitParams init_params) {
- init_params.delegate = this;
-#if !defined(OS_CHROMEOS)
- init_params.native_widget = new PlatformDesktopNativeWidget(widget_);
-#endif
- init_params.bounds = initial_bounds_;
- widget_->Init(init_params);
- }
-
- // Set the contents view to be used during Widget initialization. For Widgets
- // that use non-client views, this will be the contents_view used to
- // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise,
- // it is the ContentsView of the Widget's RootView. Ownership passes to the
- // view hierarchy during InitWidget().
- void set_contents_view(View* contents_view) {
- contents_view_ = contents_view;
- }
-
- int window_closing_count() const { return window_closing_count_; }
- const gfx::Rect& initial_bounds() { return initial_bounds_; }
-
- // WidgetDelegate overrides:
- void WindowClosing() override {
- window_closing_count_++;
- widget_ = nullptr;
- }
-
- Widget* GetWidget() override { return widget_; }
- const Widget* GetWidget() const override { return widget_; }
-
- View* GetContentsView() override {
- return contents_view_ ? contents_view_ : WidgetDelegate::GetContentsView();
- }
-
- bool ShouldAdvanceFocusToTopLevelWidget() const override {
- return true; // Same default as DefaultWidgetDelegate in widget.cc.
- }
-
- private:
- Widget* widget_;
- View* contents_view_ = nullptr;
- int window_closing_count_ = 0;
- gfx::Rect initial_bounds_ = gfx::Rect(100, 100, 200, 200);
-
- DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate);
-};
-
TEST_F(WidgetTest, WidgetInitParams) {
// Widgets are not transparent by default.
Widget::InitParams init1;
@@ -1281,49 +1159,67 @@ TEST_F(WidgetTest, GetWindowBoundsInScreen) {
widget->CloseNow();
}
-// Before being enabled on Mac, this was #ifdef(false).
-// TODO(tapted): Fix this for DesktopNativeWidgets on other platforms.
+// Non-Desktop widgets need the shell to maximize/fullscreen window.
+// Disable on Linux because windows restore to the wrong bounds.
+// See http://crbug.com/515369.
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#define MAYBE_GetRestoredBounds DISABLED_GetRestoredBounds
+#else
+#define MAYBE_GetRestoredBounds GetRestoredBounds
+#endif
+
+// Test that GetRestoredBounds() returns the original bounds of the window.
+TEST_F(WidgetTest, MAYBE_GetRestoredBounds) {
#if defined(OS_MACOSX)
-// 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());
+ // Fullscreen on Mac requires an interactive UI test, fake them here.
+ ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
+#endif
+
+ Widget* toplevel = CreateNativeDesktopWidget();
toplevel->Show();
+ // Initial restored bounds have non-zero size.
+ EXPECT_FALSE(toplevel->GetRestoredBounds().IsEmpty());
+
+ const gfx::Rect bounds(100, 100, 200, 200);
+ toplevel->SetBounds(bounds);
+ EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
+ EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
+
toplevel->Maximize();
RunPendingMessages();
#if defined(OS_MACOSX)
// Current expectation on Mac is to do nothing on Maximize.
- EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
- toplevel->GetRestoredBounds().ToString());
+ EXPECT_EQ(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
#else
- EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
- toplevel->GetRestoredBounds().ToString());
+ EXPECT_NE(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
#endif
- EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
- EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
+ EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
toplevel->Restore();
RunPendingMessages();
- EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
- toplevel->GetRestoredBounds().ToString());
+ EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
+ EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
toplevel->SetFullscreen(true);
RunPendingMessages();
if (IsTestingSnowLeopard()) {
// Fullscreen not implemented for Snow Leopard.
- EXPECT_EQ(toplevel->GetWindowBoundsInScreen().ToString(),
- toplevel->GetRestoredBounds().ToString());
+ EXPECT_EQ(toplevel->GetWindowBoundsInScreen(),
+ toplevel->GetRestoredBounds());
} else {
- EXPECT_NE(toplevel->GetWindowBoundsInScreen().ToString(),
- toplevel->GetRestoredBounds().ToString());
+ EXPECT_NE(toplevel->GetWindowBoundsInScreen(),
+ toplevel->GetRestoredBounds());
}
- EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
- EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
+ EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
+
+ toplevel->SetFullscreen(false);
+ RunPendingMessages();
+ EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
+ EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
+
+ toplevel->CloseNow();
}
-#endif
// 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
@@ -1801,28 +1697,44 @@ TEST_F(WidgetTest, EventHandlersOnRootView) {
TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
Widget* widget = CreateTopLevelNativeWidget();
View* root_view = widget->GetRootView();
+ root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
EventCountView* v1 = new EventCountView();
- v1->SetBounds(0, 0, 10, 10);
+ v1->SetBounds(5, 5, 10, 10);
root_view->AddChildView(v1);
EventCountView* v2 = new EventCountView();
- v2->SetBounds(0, 10, 10, 10);
+ v2->SetBounds(5, 15, 10, 10);
root_view->AddChildView(v2);
+ widget->Show();
+
+ // SynthesizeMouseMoveEvent does nothing until the mouse is entered.
+ widget->SynthesizeMouseMoveEvent();
+ EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_MOVED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
+
gfx::Point cursor_location(5, 5);
+ View::ConvertPointToScreen(widget->GetRootView(), &cursor_location);
ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget->OnMouseEvent(&move);
+ ui::EventDispatchDetails details =
+ WidgetTest::GetEventProcessor(widget)->OnEventFromSource(&move);
+ EXPECT_FALSE(details.dispatcher_destroyed);
- EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
- EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_MOVED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
+
+ // SynthesizeMouseMoveEvent dispatches an mousemove event.
+ widget->SynthesizeMouseMoveEvent();
+ EXPECT_EQ(2, v1->GetEventCount(ui::ET_MOUSE_MOVED));
delete v1;
- v2->SetBounds(0, 0, 10, 10);
- EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
+ v2->SetBounds(5, 5, 10, 10);
+ EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
widget->SynthesizeMouseMoveEvent();
- EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_ENTERED));
+ EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_MOVED));
widget->CloseNow();
}
@@ -2084,6 +1996,7 @@ class WidgetBoundsObserver : public WidgetObserver {
// WidgetObserver:
void OnWidgetDestroying(Widget* widget) override {
+ EXPECT_TRUE(widget->GetNativeWindow());
bounds_ = widget->GetWindowBoundsInScreen();
}
@@ -2127,7 +2040,7 @@ TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
widget->Init(params);
AnimationEndObserver animation_observer;
WidgetBoundsObserver widget_observer;
- gfx::Rect bounds(0, 0, 50, 50);
+ gfx::Rect bounds(100, 100, 50, 50);
{
// Normal animations for tests have ZERO_DURATION, make sure we are actually
// animating the movement.
@@ -2148,6 +2061,37 @@ TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
EXPECT_EQ(widget_observer.bounds(), bounds);
}
+// Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
+// and properties that depend on it are valid, when closed via CloseNow().
+TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
+ Widget* widget = CreateNativeDesktopWidget();
+ widget->Show();
+ gfx::Rect screen_rect(50, 50, 100, 100);
+ widget->SetBounds(screen_rect);
+ WidgetBoundsObserver observer;
+ widget->AddObserver(&observer);
+ widget->CloseNow();
+ EXPECT_EQ(screen_rect, observer.bounds());
+}
+
+// Test that the NativeWidget is still valid during OnNativeWidgetDestroying(),
+// and properties that depend on it are valid, when closed via Close().
+TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
+ Widget* widget = CreateNativeDesktopWidget();
+ widget->Show();
+ gfx::Rect screen_rect(50, 50, 100, 100);
+ widget->SetBounds(screen_rect);
+ WidgetBoundsObserver observer;
+ widget->AddObserver(&observer);
+ widget->Close();
+ EXPECT_EQ(gfx::Rect(), observer.bounds());
+ base::RunLoop().RunUntilIdle();
+// Broken on Linux. See http://crbug.com/515379.
+#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+ EXPECT_EQ(screen_rect, observer.bounds());
+#endif
+}
+
// Tests that we do not crash when a Widget is destroyed by going out of
// scope (as opposed to being explicitly deleted by its NativeWidget).
TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
@@ -3053,92 +2997,6 @@ TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
RunDestroyChildWidgetsTest(false, false);
}
-#if !defined(OS_CHROMEOS)
-// Provides functionality to create a window modal dialog.
-class ModalDialogDelegate : public DialogDelegateView {
- public:
- ModalDialogDelegate() {}
- ~ModalDialogDelegate() override {}
-
- // WidgetDelegate overrides.
- ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
-};
-
-// This test verifies that whether mouse events when a modal dialog is
-// displayed are eaten or recieved by the dialog.
-TEST_F(WidgetTest, WindowMouseModalityTest) {
- // Create a top level widget.
- Widget top_level_widget;
- Widget::InitParams init_params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
- init_params.show_state = ui::SHOW_STATE_NORMAL;
- gfx::Rect initial_bounds(0, 0, 500, 500);
- init_params.bounds = initial_bounds;
- init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget =
- new PlatformDesktopNativeWidget(&top_level_widget);
- top_level_widget.Init(init_params);
- top_level_widget.Show();
- EXPECT_TRUE(top_level_widget.IsVisible());
-
- // Create a view and validate that a mouse moves makes it to the view.
- EventCountView* widget_view = new EventCountView();
- widget_view->SetBounds(0, 0, 10, 10);
- top_level_widget.GetRootView()->AddChildView(widget_view);
-
- gfx::Point cursor_location_main(5, 5);
- ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, cursor_location_main,
- cursor_location_main, ui::EventTimeForNow(),
- ui::EF_NONE, ui::EF_NONE);
- ui::EventDispatchDetails details =
- GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
- ASSERT_FALSE(details.dispatcher_destroyed);
-
- EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
- widget_view->ResetCounts();
-
- // Create a modal dialog and validate that a mouse down message makes it to
- // the main view within the dialog.
-
- // This instance will be destroyed when the dialog is destroyed.
- ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
-
- Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
- dialog_delegate, NULL, top_level_widget.GetNativeView());
- modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
- EventCountView* dialog_widget_view = new EventCountView();
- dialog_widget_view->SetBounds(0, 0, 50, 50);
- modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view);
- modal_dialog_widget->Show();
- EXPECT_TRUE(modal_dialog_widget->IsVisible());
-
- gfx::Point cursor_location_dialog(100, 100);
- ui::MouseEvent mouse_down_dialog(
- ui::ET_MOUSE_PRESSED, cursor_location_dialog, cursor_location_dialog,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
- &mouse_down_dialog);
- ASSERT_FALSE(details.dispatcher_destroyed);
- EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
-
- // Send a mouse move message to the main window. It should not be received by
- // the main window as the modal dialog is still active.
- gfx::Point cursor_location_main2(6, 6);
- ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, cursor_location_main2,
- cursor_location_main2, ui::EventTimeForNow(),
- ui::EF_NONE, ui::EF_NONE);
- details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
- &mouse_down_main);
- ASSERT_FALSE(details.dispatcher_destroyed);
- EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
-
- modal_dialog_widget->CloseNow();
- top_level_widget.CloseNow();
-}
-
// Verifies nativeview visbility matches that of Widget visibility when
// SetFullscreen is invoked.
TEST_F(WidgetTest, FullscreenStatePropagated) {
@@ -3169,45 +3027,6 @@ TEST_F(WidgetTest, FullscreenStatePropagated) {
}
#endif
}
-#if defined(OS_WIN)
-
-// Tests whether we can activate the top level widget when a modal dialog is
-// active.
-TEST_F(WidgetTest, WindowModalityActivationTest) {
- TestDesktopWidgetDelegate widget_delegate;
- widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
-
- Widget* top_level_widget = widget_delegate.GetWidget();
- top_level_widget->Show();
- EXPECT_TRUE(top_level_widget->IsVisible());
-
- HWND win32_window = views::HWNDForWidget(top_level_widget);
- EXPECT_TRUE(::IsWindow(win32_window));
-
- // This instance will be destroyed when the dialog is destroyed.
- ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
-
- // We should be able to activate the window even if the WidgetDelegate
- // says no, when a modal dialog is active.
- widget_delegate.set_can_activate(false);
-
- Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
- dialog_delegate, NULL, top_level_widget->GetNativeView());
- modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
- modal_dialog_widget->Show();
- EXPECT_TRUE(modal_dialog_widget->IsVisible());
-
- LRESULT activate_result = ::SendMessage(
- win32_window,
- WM_MOUSEACTIVATE,
- reinterpret_cast<WPARAM>(win32_window),
- MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT));
- EXPECT_EQ(activate_result, MA_ACTIVATE);
-
- modal_dialog_widget->CloseNow();
-}
-#endif // defined(OS_WIN)
-#endif // !defined(OS_CHROMEOS)
namespace {