#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/hit_test.h"
+#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/point.h"
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/views_delegate.h"
+#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_deletion_observer.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/views/window/native_frame_view.h"
-#if defined(USE_AURA)
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/root_window.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
#if defined(OS_WIN)
#include "ui/views/win/hwnd_util.h"
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);
}
};
// A view that keeps track of the events it receives, and consumes all scroll
-// gesture events.
+// gesture events and ui::ET_SCROLL events.
class ScrollableEventCountView : public EventCountView {
public:
ScrollableEventCountView() {}
}
}
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
+ EventCountView::OnScrollEvent(event);
+ if (event->type() == ui::ET_SCROLL)
+ event->SetHandled();
+ }
+
DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
};
DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
};
+// Class that closes the widget (which ends up deleting it immediately) when the
+// appropriate event is received.
+class CloseWidgetView : public View {
+ public:
+ explicit CloseWidgetView(ui::EventType event_type)
+ : event_type_(event_type) {
+ }
+
+ // ui::EventHandler override:
+ virtual void OnEvent(ui::Event* event) OVERRIDE {
+ if (event->type() == event_type_) {
+ // Go through NativeWidgetPrivate to simulate what happens if the OS
+ // deletes the NativeWindow out from under us.
+ GetWidget()->native_widget_private()->CloseNow();
+ } else {
+ View::OnEvent(event);
+ if (!event->IsTouchEvent())
+ event->SetHandled();
+ }
+ }
+
+ private:
+ const ui::EventType event_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
+};
+
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;
+ widget->IsActive() ? ui::SHOW_STATE_NORMAL :
+ ui::SHOW_STATE_INACTIVE;
}
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);
}
////////////////////////////////////////////////////////////////////////////////
// |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.
//
// A platform NativeWidget subclass that updates a bag of state when it is
// destroyed.
-class OwnershipTestNativeWidget : public NativeWidgetPlatform {
+class OwnershipTestNativeWidget : public NativeWidgetAura {
public:
OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
OwnershipTestState* state)
- : NativeWidgetPlatform(delegate),
+ : NativeWidgetAura(delegate),
state_(state) {
}
virtual ~OwnershipTestNativeWidget() {
// A views NativeWidget subclass that updates a bag of state when it is
// destroyed.
-class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
+class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
public:
- OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
- OwnershipTestState* state)
- : NativeWidgetPlatformForTest(delegate),
+ OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
+ OwnershipTestState* state)
+ : NativeWidgetCapture(delegate),
state_(state) {
}
- virtual ~OwnershipTestNativeWidgetPlatform() {
+ virtual ~OwnershipTestNativeWidgetAura() {
state_->native_widget_deleted = true;
}
private:
OwnershipTestState* state_;
- DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
};
// A Widget subclass that updates a bag of state when it is destroyed.
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.parent = toplevel->GetNativeView();
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
widget->Init(params);
// Now destroy the native widget.
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
params.parent = toplevel->GetNativeView();
widget->Init(params);
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(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);
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
params.parent = toplevel->GetNativeView();
widget->Init(params);
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
params.parent = toplevel->GetNativeView();
widget->Init(params);
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = delegate_view;
widget->Init(params);
widget->StackAtTop();
widget->IsClosed();
widget->Close();
- widget->Show();
widget->Hide();
widget->Activate();
widget->Deactivate();
widget->ReleaseCapture();
widget->HasCapture();
widget->GetWorkAreaBoundsInScreen();
- // These three crash with NativeWidgetWin, so I'm assuming we don't need
- // them to work for the other NativeWidget impls.
- // widget->CenterWindow(gfx::Size(50, 60));
- // widget->GetRestoredBounds();
- // widget->ShowInactive();
}
private:
widget.native_widget_private()->CloseNow();
InvokeWidgetMethods(&widget);
}
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
{
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
EXPECT_EQ(child2, widget_bounds_changed());
}
-#if !defined(USE_AURA) && defined(OS_WIN)
+#if defined(false)
// Aura needs shell to maximize/fullscreen window.
// NativeWidgetGtk doesn't implement GetRestoredBounds.
TEST_F(WidgetTest, GetRestoredBounds) {
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.
View* container = toplevel->client_view();
Textfield* textfield = new Textfield();
- textfield->SetText(ASCIIToUTF16("some text"));
+ textfield->SetText(base::ASCIIToUTF16("some text"));
container->AddChildView(textfield);
toplevel->Show();
textfield->RequestFocus();
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);
+ contents_view->SetFocusable(true);
Widget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
// Show a bubble.
BubbleDelegateView* bubble_delegate_view =
new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT);
- bubble_delegate_view->set_focusable(true);
+ bubble_delegate_view->SetFocusable(true);
BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show();
bubble_delegate_view->RequestFocus();
EXPECT_TRUE(contents_view->HasFocus());
}
+class TestBubbleDelegateView : public BubbleDelegateView {
+ public:
+ TestBubbleDelegateView(View* anchor)
+ : BubbleDelegateView(anchor, BubbleBorder::NONE),
+ reset_controls_called_(false) {}
+ virtual ~TestBubbleDelegateView() {}
+
+ virtual bool ShouldShowCloseButton() const OVERRIDE {
+ reset_controls_called_ = true;
+ return true;
+ }
+
+ mutable bool reset_controls_called_;
+};
+
+TEST_F(WidgetTest, BubbleControlsResetOnInit) {
+ Widget* anchor = CreateTopLevelPlatformWidget();
+ anchor->Show();
+
+ TestBubbleDelegateView* bubble_delegate =
+ new TestBubbleDelegateView(anchor->client_view());
+ Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
+ EXPECT_TRUE(bubble_delegate->reset_controls_called_);
+ bubble_widget->Show();
+ bubble_widget->CloseNow();
+
+ anchor->Hide();
+ anchor->CloseNow();
+}
+
// 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, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
View* contents_view = new View;
- contents_view->set_focusable(true);
+ contents_view->SetFocusable(true);
DesktopAuraTestValidPaintWidget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
View* contents_view = new View;
- contents_view->set_focusable(true);
+ contents_view->SetFocusable(true);
DesktopAuraTestValidPaintWidget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
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;
+ init_params.layer_type = aura::WINDOW_LAYER_NOT_DRAWN;
init_params.accept_events = fullscreen;
widget_.Init(init_params);
owned_window_ = new aura::Window(&child_window_delegate_);
- owned_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ owned_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
owned_window_->SetName("TestTopLevelWindow");
if (fullscreen) {
owned_window_->SetProperty(aura::client::kShowStateKey,
ui::SHOW_STATE_FULLSCREEN);
} else {
- owned_window_->SetType(aura::client::WINDOW_TYPE_MENU);
+ owned_window_->SetType(ui::wm::WINDOW_TYPE_MENU);
}
- owned_window_->Init(ui::LAYER_TEXTURED);
+ owned_window_->Init(aura::WINDOW_LAYER_TEXTURED);
aura::client::ParentWindowWithContext(
owned_window_,
widget_.GetNativeView()->GetRootWindow(),
}
}
+ aura::Window* owned_window() {
+ return owned_window_;
+ }
+
+ views::Widget* top_level_widget() {
+ return top_level_widget_;
+ }
+
private:
views::Widget widget_;
views::Widget* top_level_widget_;
RunPendingMessages();
}
-// TODO(erg): Disabled on desktop linux until http://crbug.com/288988 is fixed.
-#if !defined(OS_LINUX)
TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupTest) {
ViewsDelegate::views_delegate = NULL;
DesktopAuraTopLevelWindowTest popup_window;
ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
RunPendingMessages();
}
-#endif
+
+// This test validates that when a top level owned popup Aura window is
+// resized, the widget is resized as well.
+TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupResizeTest) {
+ ViewsDelegate::views_delegate = NULL;
+ DesktopAuraTopLevelWindowTest popup_window;
+ ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
+ gfx::Rect(0, 0, 200, 200), false));
+
+ gfx::Rect new_size(0, 0, 400, 400);
+ popup_window.owned_window()->SetBounds(new_size);
+
+ EXPECT_EQ(popup_window.top_level_widget()->GetNativeView()->bounds().size(),
+ new_size.size());
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
+ RunPendingMessages();
+}
// Test to ensure that the aura Window's visiblity state is set to visible if
// the underlying widget is hidden and then shown.
// nested message loops from such events, nor has the code ever really dealt
// with this situation.
-// Class that closes the widget (which ends up deleting it immediately) when the
-// appropriate event is received.
-class CloseWidgetView : public View {
- public:
- explicit CloseWidgetView(ui::EventType event_type)
- : event_type_(event_type) {
- }
-
- // View overrides:
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMousePressed(event);
- return true;
- }
- virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseDragged(event);
- return true;
- }
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseReleased(event);
- }
- virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseMoved(event);
- }
- virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseEntered(event);
- }
-
- private:
- bool CloseWidget(const ui::LocatedEvent& event) {
- if (event.type() == event_type_) {
- // Go through NativeWidgetPrivate to simulate what happens if the OS
- // deletes the NativeWindow out from under us.
- GetWidget()->native_widget_private()->CloseNow();
- return true;
- }
- return false;
- }
-
- const ui::EventType event_type_;
-
- DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
-};
-
// Generates two moves (first generates enter, second real move), a press, drag
// and release stopping at |last_event_type|.
void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
- screen_bounds.CenterPoint(), 0);
- aura::RootWindowHostDelegate* rwhd =
- widget->GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate();
- rwhd->OnHostMouseEvent(&move_event);
- if (last_event_type == ui::ET_MOUSE_ENTERED)
+ screen_bounds.CenterPoint(), 0, 0);
+ ui::EventProcessor* dispatcher =
+ widget->GetNativeWindow()->GetHost()->event_processor();
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
+ if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
return;
- rwhd->OnHostMouseEvent(&move_event);
- if (last_event_type == ui::ET_MOUSE_MOVED)
+ details = dispatcher->OnEventFromSource(&move_event);
+ if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
return;
ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
- screen_bounds.CenterPoint(), 0);
- rwhd->OnHostMouseEvent(&press_event);
- if (last_event_type == ui::ET_MOUSE_PRESSED)
+ screen_bounds.CenterPoint(), 0, 0);
+ details = dispatcher->OnEventFromSource(&press_event);
+ if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
return;
gfx::Point end_point(screen_bounds.CenterPoint());
end_point.Offset(1, 1);
- ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0);
- rwhd->OnHostMouseEvent(&drag_event);
- if (last_event_type == ui::ET_MOUSE_DRAGGED)
+ ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
+ details = dispatcher->OnEventFromSource(&drag_event);
+ if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
return;
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0);
- rwhd->OnHostMouseEvent(&release_event);
+ ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
+ 0);
+ details = dispatcher->OnEventFromSource(&release_event);
+ if (details.dispatcher_destroyed)
+ return;
}
// Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
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) {
}
// Tests that event-handlers installed on the RootView get triggered correctly.
+// TODO(tdanderson): Clean up this test as part of crbug.com/355680.
TEST_F(WidgetTest, EventHandlersOnRootView) {
Widget* widget = CreateTopLevelNativeWidget();
View* root_view = widget->GetRootView();
- EventCountView* view = new EventCountView;
+ scoped_ptr<EventCountView> view(new EventCountView());
+ view->set_owned_by_client();
view->SetBounds(0, 0, 20, 20);
- root_view->AddChildView(view);
+ root_view->AddChildView(view.get());
EventCountHandler h1;
root_view->AddPreTargetHandler(&h1);
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);
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));
0, 20,
2);
widget->OnScrollEvent(&scroll);
- EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
- EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
+
+ // Unhandled scroll events are turned into wheel events and re-dispatched.
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
+
+ h1.ResetCounts();
+ view->ResetCounts();
+ h2.ResetCounts();
+
+ ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
+ gfx::Point(5, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&fling);
+ EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
+ EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
+
+ // Unhandled scroll events which are not of type ui::ET_SCROLL should not
+ // be turned into wheel events and re-dispatched.
+ EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
+
+ h1.ResetCounts();
+ view->ResetCounts();
+ h2.ResetCounts();
+
+ // Replace the child of |root_view| with a ScrollableEventCountView so that
+ // ui::ET_SCROLL events are marked as handled at the target phase.
+ root_view->RemoveChildView(view.get());
+ ScrollableEventCountView* scroll_view = new ScrollableEventCountView;
+ scroll_view->SetBounds(0, 0, 20, 20);
+ root_view->AddChildView(scroll_view);
+
+ ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
+ gfx::Point(5, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&consumed_scroll);
+
+ // The event is handled at the target phase and should not reach the
+ // post-target handler.
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
+
+ // Handled scroll events are not turned into wheel events and re-dispatched.
+ EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, scroll_view->GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
widget->CloseNow();
}
gfx::Point cursor_location(5, 5);
ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EF_NONE);
+ ui::EF_NONE, ui::EF_NONE);
widget->OnMouseEvent(&move);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
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)
+#if !defined(OS_CHROMEOS)
init_params.native_widget = new DesktopNativeWidgetAura(widget);
#endif
widget->Init(init_params);
EXPECT_EQ(1, delegate->count());
}
+class WidgetWindowTitleTest : public WidgetTest {
+ protected:
+ void RunTest(bool desktop_native_widget) {
+ Widget* widget = new Widget(); // Destroyed by CloseNow() below.
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ widget->Init(init_params);
+
+#if !defined(OS_CHROMEOS)
+ if (desktop_native_widget)
+ init_params.native_widget = new DesktopNativeWidgetAura(widget);
+#else
+ DCHECK(!desktop_native_widget)
+ << "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
+#endif
+
+ internal::NativeWidgetPrivate* native_widget =
+ widget->native_widget_private();
+
+ base::string16 empty;
+ base::string16 s1(base::UTF8ToUTF16("Title1"));
+ base::string16 s2(base::UTF8ToUTF16("Title2"));
+ base::string16 s3(base::UTF8ToUTF16("TitleLong"));
+
+ // The widget starts with no title, setting empty should not change
+ // anything.
+ EXPECT_FALSE(native_widget->SetWindowTitle(empty));
+ // Setting the title to something non-empty should cause a change.
+ EXPECT_TRUE(native_widget->SetWindowTitle(s1));
+ // Setting the title to something else with the same length should cause a
+ // change.
+ EXPECT_TRUE(native_widget->SetWindowTitle(s2));
+ // Setting the title to something else with a different length should cause
+ // a change.
+ EXPECT_TRUE(native_widget->SetWindowTitle(s3));
+ // Setting the title to the same thing twice should not cause a change.
+ EXPECT_FALSE(native_widget->SetWindowTitle(s3));
+
+ widget->CloseNow();
+ }
+};
+
+TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
+ // Use the default NativeWidget.
+ bool desktop_native_widget = false;
+ RunTest(desktop_native_widget);
+}
+
+// DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
+#if !defined(OS_CHROMEOS)
+TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
+ // Override to use a DesktopNativeWidget.
+ bool desktop_native_widget = true;
+ RunTest(desktop_native_widget);
+}
+#endif // !OS_CHROMEOS
+
// Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
class VerifyTopLevelDelegate : public TestViewsDelegate {
public:
EXPECT_TRUE(delegate->is_top_level());
}
-// A scumbag View that deletes its owning widget OnMousePressed.
-class WidgetDeleterView : public View {
- public:
- WidgetDeleterView() : View() {}
+TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
+ Widget* widget = new Widget;
+ Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_POPUP);
+ widget->Init(params);
- // Overridden from View.
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
- delete GetWidget();
- return true;
- }
+ widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
- private:
- DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
-};
+ widget->SetSize(gfx::Size(100, 100));
+ widget->Show();
+
+ aura::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
-TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
+ WidgetDeletionObserver deletion_observer(widget);
+ generator.ClickLeftButton();
+ EXPECT_FALSE(deletion_observer.IsWidgetAlive());
+
+ // Yay we did not crash!
+}
+
+TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
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->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
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);
+ aura::test::EventGenerator generator(GetContext());
+
+ WidgetDeletionObserver deletion_observer(widget);
+ generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
+ EXPECT_FALSE(deletion_observer.IsWidgetAlive());
// Yay we did not crash!
}
Widget::InitParams params(in_params);
// Deletes itself when the Widget is destroyed.
params.delegate = new GetNativeThemeFromDestructorView;
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (is_first_run) {
params.native_widget = new DesktopNativeWidgetAura(widget);
needs_second_run = true;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_MENU);
params.opacity = Widget::InitParams::OPAQUE_WINDOW;
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
params.native_widget = new DesktopNativeWidgetAura(widget);
#endif
widget->Init(params);
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);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
widget->OnMouseEvent(&press);
EXPECT_EQ(view, GetMousePressedHandler(root_view));
widget->Hide();
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);
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
widget->OnMouseEvent(&move);
EXPECT_EQ(view, GetMouseMoveHandler(root_view));
widget->Hide();
widget->Close();
}
+class GestureEndConsumerView : public View {
+ private:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ if (event->type() == ui::ET_GESTURE_END)
+ event->SetHandled();
+ }
+};
+
+TEST_F(WidgetTest, GestureHandlerNotSetOnGestureEnd) {
+ Widget* widget = CreateTopLevelNativeWidget();
+ widget->SetBounds(gfx::Rect(0, 0, 300, 300));
+ View* view = new GestureEndConsumerView();
+ view->SetBounds(0, 0, 300, 300);
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget->GetRootView());
+ root_view->AddChildView(view);
+
+ widget->Show();
+ EXPECT_EQ(NULL, GetGestureHandler(root_view));
+ ui::GestureEvent end(ui::ET_GESTURE_END, 15, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
+ widget->OnGestureEvent(&end);
+ EXPECT_EQ(NULL, GetGestureHandler(root_view));
+
+ widget->Close();
+}
+
// Test the result of Widget::GetAllChildWidgets().
TEST_F(WidgetTest, GetAllChildWidgets) {
// Create the following widget hierarchy:
Widget* top_level = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (top_level_has_desktop_native_widget_aura)
params.native_widget = new DesktopNativeWidgetAura(top_level);
#endif
Widget::InitParams child_params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
child_params.parent = top_level->GetNativeView();
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (child_has_desktop_native_widget_aura)
child_params.native_widget = new DesktopNativeWidgetAura(child);
#endif
DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
};
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
// See description of RunDestroyChildWidgetsTest(). Parent uses
// DesktopNativeWidgetAura.
TEST_F(WidgetChildDestructionTest,
RunDestroyChildWidgetsTest(false, false);
}
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
// Provides functionality to create a window modal dialog.
class ModalDialogDelegate : public DialogDelegateView {
public:
ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
cursor_location_main,
cursor_location_main,
+ ui::EF_NONE,
ui::EF_NONE);
- top_level_widget.GetNativeView()->GetDispatcher()->
- AsRootWindowHostDelegate()->OnHostMouseEvent(&move_main);
+ ui::EventDispatchDetails details = top_level_widget.GetNativeView()->
+ GetHost()->event_processor()->OnEventFromSource(&move_main);
+ ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
widget_view->ResetCounts();
ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
cursor_location_dialog,
cursor_location_dialog,
+ ui::EF_NONE,
ui::EF_NONE);
- top_level_widget.GetNativeView()->GetDispatcher()->
- AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_dialog);
+ details = top_level_widget.GetNativeView()->GetHost()->event_processor()->
+ 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
ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
cursor_location_main2,
cursor_location_main2,
+ ui::EF_NONE,
ui::EF_NONE);
- top_level_widget.GetNativeView()->GetDispatcher()->
- AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_main);
+ details = top_level_widget.GetNativeView()->GetHost()->event_processor()->
+ 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) {
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.show_state = ui::SHOW_STATE_NORMAL;
+ init_params.bounds = gfx::Rect(0, 0, 500, 500);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+
+ {
+ Widget top_level_widget;
+ top_level_widget.Init(init_params);
+ top_level_widget.SetFullscreen(true);
+ EXPECT_EQ(top_level_widget.IsVisible(),
+ top_level_widget.GetNativeView()->IsVisible());
+ top_level_widget.CloseNow();
+ }
+
+#if !defined(OS_CHROMEOS)
+ {
+ Widget top_level_widget;
+ init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
+ top_level_widget.Init(init_params);
+ top_level_widget.SetFullscreen(true);
+ EXPECT_EQ(top_level_widget.IsVisible(),
+ top_level_widget.GetNativeView()->IsVisible());
+ top_level_widget.CloseNow();
+ }
+#endif
+}
+
#if defined(OS_WIN)
// Provides functionality to test widget activation via an activation flag
#endif
#endif
+TEST_F(WidgetTest, ShowCreatesActiveWindow) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->Show();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, ShowInactive) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->ShowInactive();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, ShowInactiveAfterShow) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->Show();
+ widget->ShowInactive();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, ShowAfterShowInactive) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->ShowInactive();
+ widget->Show();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+}
+
+#if !defined(OS_CHROMEOS)
+TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+ widget->Show();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ Widget widget2;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.can_activate = false;
+ params.native_widget = new DesktopNativeWidgetAura(&widget2);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget2.Init(params);
+ widget2.Show();
+
+ EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+ widget2.CloseNow();
+}
+#endif
+
+namespace {
+
+class FullscreenAwareFrame : public views::NonClientFrameView {
+ public:
+ explicit FullscreenAwareFrame(views::Widget* widget)
+ : widget_(widget), fullscreen_layout_called_(false) {}
+ virtual ~FullscreenAwareFrame() {}
+
+ // views::NonClientFrameView overrides:
+ virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
+ return gfx::Rect();
+ }
+ virtual gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const OVERRIDE {
+ return gfx::Rect();
+ }
+ virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
+ return HTNOWHERE;
+ }
+ virtual void GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) OVERRIDE {}
+ virtual void ResetWindowControls() OVERRIDE {}
+ virtual void UpdateWindowIcon() OVERRIDE {}
+ virtual void UpdateWindowTitle() OVERRIDE {}
+
+ // views::View overrides:
+ virtual void Layout() OVERRIDE {
+ if (widget_->IsFullscreen())
+ fullscreen_layout_called_ = true;
+ }
+
+ bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
+
+ private:
+ views::Widget* widget_;
+ bool fullscreen_layout_called_;
+
+ DISALLOW_COPY_AND_ASSIGN(FullscreenAwareFrame);
+};
+
+} // namespace
+
+// Tests that frame Layout is called when a widget goes fullscreen without
+// changing its size or title.
+TEST_F(WidgetTest, FullscreenFrameLayout) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+ FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget);
+ widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
+
+ widget->Maximize();
+ RunPendingMessages();
+
+ EXPECT_FALSE(frame->fullscreen_layout_called());
+ widget->SetFullscreen(true);
+ widget->Show();
+ RunPendingMessages();
+ EXPECT_TRUE(frame->fullscreen_layout_called());
+
+ widget->CloseNow();
+}
+
+#if !defined(OS_CHROMEOS)
+namespace {
+
+// Trivial WidgetObserverTest that invokes Widget::IsActive() from
+// OnWindowDestroying.
+class IsActiveFromDestroyObserver : public WidgetObserver {
+ public:
+ IsActiveFromDestroyObserver() {}
+ virtual ~IsActiveFromDestroyObserver() {}
+ virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
+ widget->IsActive();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IsActiveFromDestroyObserver);
+};
+
+} // namespace
+
+// Verifies Widget::IsActive() invoked from
+// WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash.
+TEST_F(WidgetTest, IsActiveFromDestroy) {
+ // Create two widgets, one a child of the other.
+ IsActiveFromDestroyObserver observer;
+ Widget parent_widget;
+ Widget::InitParams parent_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ parent_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
+ parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ parent_widget.Init(parent_params);
+ parent_widget.Show();
+
+ Widget child_widget;
+ Widget::InitParams child_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ child_params.context = parent_widget.GetNativeView();
+ child_widget.Init(child_params);
+ child_widget.AddObserver(&observer);
+ child_widget.Show();
+
+ parent_widget.CloseNow();
+}
+#endif
+
} // namespace test
} // namespace views