diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-22 07:30:30 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-22 07:30:30 +0000 |
commit | 425969e28b738207ec204a057f294345ea5560de (patch) | |
tree | 53ac4d874b1d24d833b46af1403fbf4b2ba2a74c /ui/views/widget | |
parent | bd1dce86395428a44c830a33e11eefc0519fbfad (diff) | |
download | chromium_src-425969e28b738207ec204a057f294345ea5560de.zip chromium_src-425969e28b738207ec204a057f294345ea5560de.tar.gz chromium_src-425969e28b738207ec204a057f294345ea5560de.tar.bz2 |
Makes aura NativeWidget implementations no-op if NativeView destroyed.
Many win32 functions silently do nothing if passed an invalid HWND,
which is why we haven't had to worry about this with
NativeWidgetWin. I'm including a test that exercises the interesting
public methods of Widget.
BUG=275767
TEST=covered by tests
R=ananta@chromium.org
Review URL: https://chromiumcodereview.appspot.com/22880031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218929 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/views/widget')
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_native_widget_aura.cc | 119 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_native_widget_aura.h | 4 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.cc | 116 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.h | 3 | ||||
-rw-r--r-- | ui/views/widget/widget_unittest.cc | 93 |
5 files changed, 265 insertions, 70 deletions
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 476f567..3dcf931 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -315,15 +315,16 @@ Widget* DesktopNativeWidgetAura::GetTopLevelWidget() { } const ui::Compositor* DesktopNativeWidgetAura::GetCompositor() const { - return window_->layer()->GetCompositor(); + return window_ ? window_->layer()->GetCompositor() : NULL; } ui::Compositor* DesktopNativeWidgetAura::GetCompositor() { - return window_->layer()->GetCompositor(); + return const_cast<ui::Compositor*>( + const_cast<const DesktopNativeWidgetAura*>(this)->GetCompositor()); } ui::Layer* DesktopNativeWidgetAura::GetLayer() { - return window_->layer(); + return window_ ? window_->layer() : NULL; } void DesktopNativeWidgetAura::ReorderNativeViews() { @@ -335,11 +336,12 @@ void DesktopNativeWidgetAura::ViewRemoved(View* view) { void DesktopNativeWidgetAura::SetNativeWindowProperty(const char* name, void* value) { - window_->SetNativeWindowProperty(name, value); + if (window_) + window_->SetNativeWindowProperty(name, value); } void* DesktopNativeWidgetAura::GetNativeWindowProperty(const char* name) const { - return window_->GetNativeWindowProperty(name); + return window_ ? window_->GetNativeWindowProperty(name) : NULL; } TooltipManager* DesktopNativeWidgetAura::GetTooltipManager() const { @@ -347,6 +349,9 @@ TooltipManager* DesktopNativeWidgetAura::GetTooltipManager() const { } void DesktopNativeWidgetAura::SetCapture() { + if (!window_) + return; + window_->SetCapture(); // aura::Window doesn't implicitly update capture on the RootWindowHost, so // we have to do that manually. @@ -355,6 +360,9 @@ void DesktopNativeWidgetAura::SetCapture() { } void DesktopNativeWidgetAura::ReleaseCapture() { + if (!window_) + return; + window_->ReleaseCapture(); // aura::Window doesn't implicitly update capture on the RootWindowHost, so // we have to do that manually. @@ -363,7 +371,8 @@ void DesktopNativeWidgetAura::ReleaseCapture() { } bool DesktopNativeWidgetAura::HasCapture() const { - return window_->HasCapture() && desktop_root_window_host_->HasCapture(); + return window_ && window_->HasCapture() && + desktop_root_window_host_->HasCapture(); } InputMethod* DesktopNativeWidgetAura::CreateInputMethod() { @@ -377,22 +386,26 @@ internal::InputMethodDelegate* } void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) { - desktop_root_window_host_->CenterWindow(size); + if (window_) + desktop_root_window_host_->CenterWindow(size); } void DesktopNativeWidgetAura::GetWindowPlacement( gfx::Rect* bounds, ui::WindowShowState* maximized) const { - desktop_root_window_host_->GetWindowPlacement(bounds, maximized); + if (window_) + desktop_root_window_host_->GetWindowPlacement(bounds, maximized); } void DesktopNativeWidgetAura::SetWindowTitle(const string16& title) { - desktop_root_window_host_->SetWindowTitle(title); + if (window_) + desktop_root_window_host_->SetWindowTitle(title); } void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { - desktop_root_window_host_->SetWindowIcons(window_icon, app_icon); + if (window_) + desktop_root_window_host_->SetWindowIcons(window_icon, app_icon); } void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) { @@ -403,18 +416,23 @@ void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) { } gfx::Rect DesktopNativeWidgetAura::GetWindowBoundsInScreen() const { - return desktop_root_window_host_->GetWindowBoundsInScreen(); + return window_ ? desktop_root_window_host_->GetWindowBoundsInScreen() : + gfx::Rect(); } gfx::Rect DesktopNativeWidgetAura::GetClientAreaBoundsInScreen() const { - return desktop_root_window_host_->GetClientAreaBoundsInScreen(); + return window_ ? desktop_root_window_host_->GetClientAreaBoundsInScreen() : + gfx::Rect(); } gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const { - return desktop_root_window_host_->GetRestoredBounds(); + return window_ ? desktop_root_window_host_->GetRestoredBounds() : gfx::Rect(); } void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) { + if (!window_) + return; + float scale = 1; aura::RootWindow* root = root_window_.get(); if (root) { @@ -428,7 +446,8 @@ void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) { } void DesktopNativeWidgetAura::SetSize(const gfx::Size& size) { - desktop_root_window_host_->SetSize(size); + if (window_) + desktop_root_window_host_->SetSize(size); } void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) { @@ -441,98 +460,117 @@ void DesktopNativeWidgetAura::StackBelow(gfx::NativeView native_view) { } void DesktopNativeWidgetAura::SetShape(gfx::NativeRegion shape) { - desktop_root_window_host_->SetShape(shape); + if (window_) + desktop_root_window_host_->SetShape(shape); } void DesktopNativeWidgetAura::Close() { + if (!window_) + return; desktop_root_window_host_->Close(); - if (window_) - window_->SuppressPaint(); + window_->SuppressPaint(); } void DesktopNativeWidgetAura::CloseNow() { - desktop_root_window_host_->CloseNow(); + if (window_) + desktop_root_window_host_->CloseNow(); } void DesktopNativeWidgetAura::Show() { + if (!window_) + return; desktop_root_window_host_->AsRootWindowHost()->Show(); window_->Show(); } void DesktopNativeWidgetAura::Hide() { + if (!window_) + return; desktop_root_window_host_->AsRootWindowHost()->Hide(); - if (window_) - window_->Hide(); + window_->Hide(); } void DesktopNativeWidgetAura::ShowMaximizedWithBounds( const gfx::Rect& restored_bounds) { + if (!window_) + return; desktop_root_window_host_->ShowMaximizedWithBounds(restored_bounds); window_->Show(); } void DesktopNativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) { + if (!window_) + return; desktop_root_window_host_->ShowWindowWithState(state); window_->Show(); } bool DesktopNativeWidgetAura::IsVisible() const { - return desktop_root_window_host_->IsVisible(); + return window_ && desktop_root_window_host_->IsVisible(); } void DesktopNativeWidgetAura::Activate() { - desktop_root_window_host_->Activate(); + if (window_) + desktop_root_window_host_->Activate(); } void DesktopNativeWidgetAura::Deactivate() { - desktop_root_window_host_->Deactivate(); + if (window_) + desktop_root_window_host_->Deactivate(); } bool DesktopNativeWidgetAura::IsActive() const { - return desktop_root_window_host_->IsActive(); + return window_ && desktop_root_window_host_->IsActive(); } void DesktopNativeWidgetAura::SetAlwaysOnTop(bool always_on_top) { - desktop_root_window_host_->SetAlwaysOnTop(always_on_top); + if (window_) + desktop_root_window_host_->SetAlwaysOnTop(always_on_top); } void DesktopNativeWidgetAura::Maximize() { - desktop_root_window_host_->Maximize(); + if (window_) + desktop_root_window_host_->Maximize(); } void DesktopNativeWidgetAura::Minimize() { - desktop_root_window_host_->Minimize(); + if (window_) + desktop_root_window_host_->Minimize(); } bool DesktopNativeWidgetAura::IsMaximized() const { - return desktop_root_window_host_->IsMaximized(); + return window_ && desktop_root_window_host_->IsMaximized(); } bool DesktopNativeWidgetAura::IsMinimized() const { - return desktop_root_window_host_->IsMinimized(); + return window_ && desktop_root_window_host_->IsMinimized(); } void DesktopNativeWidgetAura::Restore() { - desktop_root_window_host_->Restore(); + if (window_) + desktop_root_window_host_->Restore(); } void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen) { - desktop_root_window_host_->SetFullscreen(fullscreen); + if (window_) + desktop_root_window_host_->SetFullscreen(fullscreen); } bool DesktopNativeWidgetAura::IsFullscreen() const { - return desktop_root_window_host_->IsFullscreen(); + return window_ && desktop_root_window_host_->IsFullscreen(); } void DesktopNativeWidgetAura::SetOpacity(unsigned char opacity) { - desktop_root_window_host_->SetOpacity(opacity); + if (window_) + desktop_root_window_host_->SetOpacity(opacity); } void DesktopNativeWidgetAura::SetUseDragFrame(bool use_drag_frame) { } void DesktopNativeWidgetAura::FlashFrame(bool flash_frame) { - desktop_root_window_host_->FlashFrame(flash_frame); + if (window_) + desktop_root_window_host_->FlashFrame(flash_frame); } void DesktopNativeWidgetAura::RunShellDrag( @@ -558,6 +596,8 @@ void DesktopNativeWidgetAura::SetCursor(gfx::NativeCursor cursor) { } bool DesktopNativeWidgetAura::IsMouseEventsEnabled() const { + if (!window_) + return false; aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(window_->GetRootWindow()); return cursor_client ? cursor_client->IsMouseEventsEnabled() : true; @@ -577,6 +617,9 @@ gfx::Rect DesktopNativeWidgetAura::GetWorkAreaBoundsInScreen() const { } void DesktopNativeWidgetAura::SetInactiveRenderingDisabled(bool value) { + if (!window_) + return; + if (!value) { active_window_observer_.reset(); } else { @@ -588,16 +631,20 @@ void DesktopNativeWidgetAura::SetInactiveRenderingDisabled(bool value) { Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop( const gfx::Vector2d& drag_offset, Widget::MoveLoopSource source) { + if (!window_) + return Widget::MOVE_LOOP_CANCELED; return desktop_root_window_host_->RunMoveLoop(drag_offset, source); } void DesktopNativeWidgetAura::EndMoveLoop() { - desktop_root_window_host_->EndMoveLoop(); + if (window_) + desktop_root_window_host_->EndMoveLoop(); } void DesktopNativeWidgetAura::SetVisibilityChangedAnimationsEnabled( bool value) { - desktop_root_window_host_->SetVisibilityChangedAnimationsEnabled(value); + if (window_) + desktop_root_window_host_->SetVisibilityChangedAnimationsEnabled(value); } ui::NativeTheme* DesktopNativeWidgetAura::GetNativeTheme() const { diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index b98e1cc..b497440 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -224,7 +224,11 @@ class VIEWS_EXPORT DesktopNativeWidgetAura // Ownership passed to RootWindow on Init. DesktopRootWindowHost* desktop_root_window_host_; + + // The content of |root_window_|. WARNING: this may be NULL if deleted out + // from under us. aura::Window* window_; + internal::NativeWidgetDelegate* native_widget_delegate_; scoped_ptr<aura::client::StackingClient> stacking_client_; diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 8c9ad02..8a80068 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -222,15 +222,15 @@ Widget* NativeWidgetAura::GetTopLevelWidget() { } const ui::Compositor* NativeWidgetAura::GetCompositor() const { - return window_->layer()->GetCompositor(); + return window_ ? window_->layer()->GetCompositor() : NULL; } ui::Compositor* NativeWidgetAura::GetCompositor() { - return window_->layer()->GetCompositor(); + return window_ ? window_->layer()->GetCompositor() : NULL; } ui::Layer* NativeWidgetAura::GetLayer() { - return window_->layer(); + return window_ ? window_->layer() : NULL; } void NativeWidgetAura::ReorderNativeViews() { @@ -256,18 +256,22 @@ TooltipManager* NativeWidgetAura::GetTooltipManager() const { } void NativeWidgetAura::SetCapture() { - window_->SetCapture(); + if (window_) + window_->SetCapture(); } void NativeWidgetAura::ReleaseCapture() { - window_->ReleaseCapture(); + if (window_) + window_->ReleaseCapture(); } bool NativeWidgetAura::HasCapture() const { - return window_->HasCapture(); + return window_ && window_->HasCapture(); } InputMethod* NativeWidgetAura::CreateInputMethod() { + if (!window_) + return NULL; aura::RootWindow* root_window = window_->GetRootWindow(); ui::InputMethod* host = root_window->GetProperty(aura::client::kRootWindowInputMethodKey); @@ -279,6 +283,9 @@ internal::InputMethodDelegate* NativeWidgetAura::GetInputMethodDelegate() { } void NativeWidgetAura::CenterWindow(const gfx::Size& size) { + if (!window_) + return; + gfx::Rect parent_bounds(window_->parent()->GetBoundsInRootWindow()); // When centering window, we take the intersection of the host and // the parent. We assume the root window represents the visible @@ -330,11 +337,13 @@ void NativeWidgetAura::GetWindowPlacement( ui::WindowShowState* show_state) const { // The interface specifies returning restored bounds, not current bounds. *bounds = GetRestoredBounds(); - *show_state = window_->GetProperty(aura::client::kShowStateKey); + *show_state = window_ ? window_->GetProperty(aura::client::kShowStateKey) : + ui::SHOW_STATE_DEFAULT; } void NativeWidgetAura::SetWindowTitle(const string16& title) { - window_->set_title(title); + if (window_) + window_->set_title(title); } void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon, @@ -348,16 +357,19 @@ void NativeWidgetAura::InitModalType(ui::ModalType modal_type) { } gfx::Rect NativeWidgetAura::GetWindowBoundsInScreen() const { - return window_->GetBoundsInScreen(); + return window_ ? window_->GetBoundsInScreen() : gfx::Rect(); } gfx::Rect NativeWidgetAura::GetClientAreaBoundsInScreen() const { // View-to-screen coordinate system transformations depend on this returning // the full window bounds, for example View::ConvertPointToScreen(). - return window_->GetBoundsInScreen(); + return window_ ? window_->GetBoundsInScreen() : gfx::Rect(); } gfx::Rect NativeWidgetAura::GetRestoredBounds() const { + if (!window_) + return gfx::Rect(); + // Restored bounds should only be relevant if the window is minimized or // maximized. However, in some places the code expects GetRestoredBounds() // to return the current window bounds if the window is not in either state. @@ -372,6 +384,9 @@ gfx::Rect NativeWidgetAura::GetRestoredBounds() const { } void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) { + if (!window_) + return; + aura::RootWindow* root = window_->GetRootWindow(); if (root) { aura::client::ScreenPositionClient* screen_position_client = @@ -387,20 +402,24 @@ void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) { } void NativeWidgetAura::SetSize(const gfx::Size& size) { - window_->SetBounds(gfx::Rect(window_->bounds().origin(), size)); + if (window_) + window_->SetBounds(gfx::Rect(window_->bounds().origin(), size)); } void NativeWidgetAura::StackAbove(gfx::NativeView native_view) { - if (window_->parent() && window_->parent() == native_view->parent()) + if (window_ && window_->parent() && + window_->parent() == native_view->parent()) window_->parent()->StackChildAbove(window_, native_view); } void NativeWidgetAura::StackAtTop() { - window_->parent()->StackChildAtTop(window_); + if (window_) + window_->parent()->StackChildAtTop(window_); } void NativeWidgetAura::StackBelow(gfx::NativeView native_view) { - if (window_->parent() && window_->parent() == native_view->parent()) + if (window_ && window_->parent() && + window_->parent() == native_view->parent()) window_->parent()->StackChildBelow(window_, native_view); } @@ -438,7 +457,8 @@ void NativeWidgetAura::Show() { } void NativeWidgetAura::Hide() { - window_->Hide(); + if (window_) + window_->Hide(); } void NativeWidgetAura::ShowMaximizedWithBounds( @@ -448,6 +468,9 @@ void NativeWidgetAura::ShowMaximizedWithBounds( } void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) { + if (!window_) + return; + if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN) window_->SetProperty(aura::client::kShowStateKey, state); window_->Show(); @@ -466,10 +489,13 @@ void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) { } bool NativeWidgetAura::IsVisible() const { - return window_->IsVisible(); + return window_ && window_->IsVisible(); } void NativeWidgetAura::Activate() { + if (!window_) + return; + // We don't necessarily have a root window yet. This can happen with // constrained windows. if (window_->GetRootWindow()) { @@ -481,43 +507,50 @@ void NativeWidgetAura::Activate() { } void NativeWidgetAura::Deactivate() { + if (!window_) + return; aura::client::GetActivationClient(window_->GetRootWindow())->DeactivateWindow( window_); } bool NativeWidgetAura::IsActive() const { - return aura::client::GetActivationClient(window_->GetRootWindow())-> - GetActiveWindow() == window_; + return window_ && + aura::client::GetActivationClient(window_->GetRootWindow())-> + GetActiveWindow() == window_; } void NativeWidgetAura::SetAlwaysOnTop(bool on_top) { - window_->SetProperty(aura::client::kAlwaysOnTopKey, on_top); + if (window_) + window_->SetProperty(aura::client::kAlwaysOnTopKey, on_top); } void NativeWidgetAura::Maximize() { - window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); + if (window_) + window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); } void NativeWidgetAura::Minimize() { - window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); + if (window_) + window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); } bool NativeWidgetAura::IsMaximized() const { - return window_->GetProperty(aura::client::kShowStateKey) == + return window_ && window_->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_MAXIMIZED; } bool NativeWidgetAura::IsMinimized() const { - return window_->GetProperty(aura::client::kShowStateKey) == + return window_ && window_->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_MINIMIZED; } void NativeWidgetAura::Restore() { - window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); + if (window_) + window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); } void NativeWidgetAura::SetFullscreen(bool fullscreen) { - if (IsFullscreen() == fullscreen) + if (!window_ || IsFullscreen() == fullscreen) return; // Nothing to do. // Save window state before entering full screen so that it could restored @@ -531,12 +564,13 @@ void NativeWidgetAura::SetFullscreen(bool fullscreen) { } bool NativeWidgetAura::IsFullscreen() const { - return window_->GetProperty(aura::client::kShowStateKey) == + return window_ && window_->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_FULLSCREEN; } void NativeWidgetAura::SetOpacity(unsigned char opacity) { - window_->layer()->SetOpacity(opacity / 255.0); + if (window_) + window_->layer()->SetOpacity(opacity / 255.0); } void NativeWidgetAura::SetUseDragFrame(bool use_drag_frame) { @@ -544,7 +578,8 @@ void NativeWidgetAura::SetUseDragFrame(bool use_drag_frame) { } void NativeWidgetAura::FlashFrame(bool flash) { - window_->SetProperty(aura::client::kDrawAttentionKey, flash); + if (window_) + window_->SetProperty(aura::client::kDrawAttentionKey, flash); } void NativeWidgetAura::RunShellDrag(View* view, @@ -552,7 +587,8 @@ void NativeWidgetAura::RunShellDrag(View* view, const gfx::Point& location, int operation, ui::DragDropTypes::DragEventSource source) { - views::RunShellDrag(window_, data, location, operation, source); + if (window_) + views::RunShellDrag(window_, data, location, operation, source); } void NativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) { @@ -569,6 +605,8 @@ void NativeWidgetAura::SetCursor(gfx::NativeCursor cursor) { } bool NativeWidgetAura::IsMouseEventsEnabled() const { + if (!window_) + return false; aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(window_->GetRootWindow()); return cursor_client ? cursor_client->IsMouseEventsEnabled() : true; @@ -581,11 +619,16 @@ void NativeWidgetAura::ClearNativeFocus() { } gfx::Rect NativeWidgetAura::GetWorkAreaBoundsInScreen() const { - return gfx::Screen::GetScreenFor(GetNativeView())-> - GetDisplayNearestWindow(GetNativeView()).work_area(); + if (!window_) + return gfx::Rect(); + return gfx::Screen::GetScreenFor(window_)-> + GetDisplayNearestWindow(window_).work_area(); } void NativeWidgetAura::SetInactiveRenderingDisabled(bool value) { + if (!window_) + return; + if (!value) { active_window_observer_.reset(); } else { @@ -597,7 +640,7 @@ void NativeWidgetAura::SetInactiveRenderingDisabled(bool value) { Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop( const gfx::Vector2d& drag_offset, Widget::MoveLoopSource source) { - if (window_->parent() && + if (window_ && window_->parent() && aura::client::GetWindowMoveClient(window_->parent())) { SetCapture(); aura::client::WindowMoveSource window_move_source = @@ -614,14 +657,15 @@ Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop( } void NativeWidgetAura::EndMoveLoop() { - if (window_->parent() && + if (window_ && window_->parent() && aura::client::GetWindowMoveClient(window_->parent())) { aura::client::GetWindowMoveClient(window_->parent())->EndMoveLoop(); } } void NativeWidgetAura::SetVisibilityChangedAnimationsEnabled(bool value) { - window_->SetProperty(aura::client::kAnimationsDisabledKey, !value); + if (window_) + window_->SetProperty(aura::client::kAnimationsDisabledKey, !value); } ui::NativeTheme* NativeWidgetAura::GetNativeTheme() const { @@ -759,6 +803,7 @@ scoped_refptr<ui::Texture> NativeWidgetAura::CopyTexture() { // NativeWidgetAura, ui::EventHandler implementation: void NativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) { + DCHECK(window_); if (event->is_char()) { // If a ui::InputMethod object is attached to the root window, character // events are handled inside the object and are not passed to this function. @@ -775,6 +820,7 @@ void NativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) { } void NativeWidgetAura::OnMouseEvent(ui::MouseEvent* event) { + DCHECK(window_); DCHECK(window_->IsVisible()); if (event->type() == ui::ET_MOUSEWHEEL) { delegate_->OnMouseEvent(event); @@ -792,11 +838,13 @@ void NativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) { } void NativeWidgetAura::OnTouchEvent(ui::TouchEvent* event) { + DCHECK(window_); DCHECK(window_->IsVisible()); delegate_->OnTouchEvent(event); } void NativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) { + DCHECK(window_); DCHECK(window_->IsVisible()); delegate_->OnGestureEvent(event); } diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h index 57271e8..6e736a5 100644 --- a/ui/views/widget/native_widget_aura.h +++ b/ui/views/widget/native_widget_aura.h @@ -189,6 +189,9 @@ class VIEWS_EXPORT NativeWidgetAura internal::NativeWidgetDelegate* delegate_; + // WARNING: set to NULL when destroyed. As the Widget is not necessarily + // destroyed along with |window_| all usage of |window_| should first verify + // non-NULL. aura::Window* window_; // See class documentation for Widget in widget.h for a note about ownership. diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index b9e32d6..4e195cf 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc @@ -941,6 +941,99 @@ TEST_F(WidgetOwnershipTest, } //////////////////////////////////////////////////////////////////////////////// +// Test to verify using various Widget methods doesn't crash when the underlying +// NativeView is destroyed. +// +class WidgetWithDestroyedNativeViewTest : public ViewsTestBase { + public: + WidgetWithDestroyedNativeViewTest() {} + virtual ~WidgetWithDestroyedNativeViewTest() {} + + void InvokeWidgetMethods(Widget* widget) { + widget->GetNativeView(); + widget->GetNativeWindow(); + ui::Accelerator accelerator; + widget->GetAccelerator(0, &accelerator); + widget->GetTopLevelWidget(); + widget->GetWindowBoundsInScreen(); + widget->GetClientAreaBoundsInScreen(); + widget->SetBounds(gfx::Rect(0, 0, 100, 80)); + widget->SetSize(gfx::Size(10, 11)); + widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140)); + widget->SetVisibilityChangedAnimationsEnabled(false); + widget->StackAtTop(); + widget->IsClosed(); + widget->Close(); + widget->Show(); + widget->Hide(); + widget->Activate(); + widget->Deactivate(); + widget->IsActive(); + widget->DisableInactiveRendering(); + widget->SetAlwaysOnTop(true); + widget->Maximize(); + widget->Minimize(); + widget->Restore(); + widget->IsMaximized(); + widget->IsFullscreen(); + widget->SetOpacity(0); + widget->SetUseDragFrame(true); + widget->FlashFrame(true); + widget->IsVisible(); + widget->GetThemeProvider(); + widget->GetNativeTheme(); + widget->GetFocusManager(); + widget->GetInputMethod(); + widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2)); + widget->IsMouseEventsEnabled(); + widget->SetNativeWindowProperty("xx", widget); + widget->GetNativeWindowProperty("xx"); + widget->GetFocusTraversable(); + widget->GetLayer(); + widget->ReorderNativeViews(); + widget->SetCapture(widget->GetRootView()); + widget->ReleaseCapture(); + widget->HasCapture(); + widget->TooltipTextChanged(widget->GetRootView()); + 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: + DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest); +}; + +TEST_F(WidgetWithDestroyedNativeViewTest, Test) { + { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(params); + widget.Show(); + + widget.native_widget_private()->CloseNow(); + InvokeWidgetMethods(&widget); + } +#if defined(USE_AURA) && !defined(OS_CHROMEOS) + { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + params.native_widget = new DesktopNativeWidgetAura(&widget); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(params); + widget.Show(); + + widget.native_widget_private()->CloseNow(); + InvokeWidgetMethods(&widget); + } +#endif +} + +//////////////////////////////////////////////////////////////////////////////// // Widget observer tests. // |