From 8754d669dc321e10b5292cb655e4cc58aeedc861 Mon Sep 17 00:00:00 2001 From: Aleksandar Stojiljkovic Date: Mon, 29 Feb 2016 12:31:12 +0200 Subject: [PATCH] Page Visibility API: visibilitychange on Windows screen lock/unlock BUG=XWALK-5503 Some OSs (e.g. Windows and Linux) don't mark windows as hiden on screen lock or when other opaque windows fully cover them. Note that e.g. OSX and Android do this while Windows and Linux don't. OnSoftVisibilityChanged enables that OS window state is kept as is (on Linux and Windows) and that e.g. power saving PageVisibility API is still properly triggered. The first patch here targets Windows and screen lock. branch pagevis --- ui/views/controls/native/native_view_host.cc | 16 ++++++++++++++++ ui/views/controls/native/native_view_host.h | 1 + ui/views/view.cc | 6 ++++++ ui/views/view.h | 4 ++++ .../desktop_aura/desktop_window_tree_host_win.cc | 4 ++++ .../desktop_aura/desktop_window_tree_host_win.h | 1 + ui/views/widget/native_widget_delegate.h | 8 ++++++++ ui/views/widget/widget.cc | 5 +++++ ui/views/widget/widget.h | 1 + ui/views/win/hwnd_message_handler.cc | 8 +++++++- ui/views/win/hwnd_message_handler_delegate.h | 6 ++++++ 11 files changed, 59 insertions(+), 1 deletion(-) diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc index 452e5966b4833..ea6db3839a757 100644 --- a/ui/views/controls/native/native_view_host.cc +++ b/ui/views/controls/native/native_view_host.cc @@ -127,6 +127,22 @@ void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) { Layout(); } +void NativeViewHost::OnSoftVisibilityChanged(bool visible) { + if (!native_view_ || !native_wrapper_.get()) + return; + + if (GetVisibleBounds().IsEmpty()) + return; + + // If the widget wasn't .e.g. minimized, hide and show would trigger + // PageVisibility API, enabling JS to save power while screen is locked. + if (visible) { + Layout(); + } else { + native_wrapper_->HideWidget(); + } +} + bool NativeViewHost::GetNeedsNotificationWhenVisibleBoundsChange() const { // The native widget is placed relative to the root. As such, we need to // know when the position of any ancestor changes, or our visibility relative diff --git a/ui/views/controls/native/native_view_host.h b/ui/views/controls/native/native_view_host.h index 6b9aa0ea4ac56..d5ff064e18a3b 100644 --- a/ui/views/controls/native/native_view_host.h +++ b/ui/views/controls/native/native_view_host.h @@ -83,6 +83,7 @@ class VIEWS_EXPORT NativeViewHost : public View { void OnFocus() override; gfx::NativeViewAccessible GetNativeViewAccessible() override; gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override; + void OnSoftVisibilityChanged(bool visible) override; protected: bool GetNeedsNotificationWhenVisibleBoundsChange() const override; diff --git a/ui/views/view.cc b/ui/views/view.cc index be3bbf5b7ed29..6f7c6c30c6a94 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc @@ -1893,6 +1893,12 @@ void View::PropagateNativeThemeChanged(const ui::NativeTheme* theme) { OnNativeThemeChanged(theme); } +void View::PropagateSoftVisibilityChanged(bool visible) { + for (int i = 0, count = child_count(); i < count; ++i) + child_at(i)->PropagateSoftVisibilityChanged(visible); + OnSoftVisibilityChanged(visible); +} + // Size and disposition -------------------------------------------------------- void View::PropagateVisibilityNotifications(View* start, bool is_visible) { diff --git a/ui/views/view.h b/ui/views/view.h index 6b45c6313baf3..ef6eaec89ea7b 100644 --- a/ui/views/view.h +++ b/ui/views/view.h @@ -1077,6 +1077,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // FocusManager manages this view. virtual void NativeViewHierarchyChanged(); + virtual void OnSoftVisibilityChanged(bool visible) {} + // Painting ------------------------------------------------------------------ // Responsible for calling Paint() on child Views. Override to control the @@ -1285,6 +1287,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // VisibilityChanged(). void VisibilityChangedImpl(View* starting_from, bool is_visible); + void PropagateSoftVisibilityChanged(bool visible); + // Responsible for propagating bounds change notifications to relevant // views. void BoundsChanged(const gfx::Rect& previous_bounds); diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index de96b6309b1c3..baffe1ccfc85d 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -808,6 +808,10 @@ void DesktopWindowTreeHostWin::HandleVisibilityChanged(bool visible) { native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible); } +void DesktopWindowTreeHostWin::HandleSoftVisibilityChanged(bool visible) { + native_widget_delegate_->OnSoftVisibilityChanged(visible); +} + void DesktopWindowTreeHostWin::HandleClientSizeChanged( const gfx::Size& new_size) { if (dispatcher()) diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h index e71604dd92827..c828053bde710 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h @@ -197,6 +197,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin void HandleWindowSizeChanging() override; void HandleWindowSizeChanged() override; void HandleWindowScaleFactorChanged(float window_scale_factor) override; + void HandleSoftVisibilityChanged(bool visible) override; Widget* GetWidget(); const Widget* GetWidget() const; diff --git a/ui/views/widget/native_widget_delegate.h b/ui/views/widget/native_widget_delegate.h index e6c3b84ea042a..d73274750c85b 100644 --- a/ui/views/widget/native_widget_delegate.h +++ b/ui/views/widget/native_widget_delegate.h @@ -71,6 +71,14 @@ class VIEWS_EXPORT NativeWidgetDelegate { // Called when the window is shown/hidden. virtual void OnNativeWidgetVisibilityChanged(bool visible) = 0; + // Some OSs (e.g. Windows and Linux) don't mark windows as hiden on screen + // lock or when other opaque windows fully cover them. + // Note that e.g. OSX and Android do this while Windows and Linux don't. + // OnSoftVisibilityChanged enables that OS window state is kept as is (on + // Linux and Windows) and that e.g. power saving PageVisibility API is still + // properly triggered. + virtual void OnSoftVisibilityChanged(bool visible) = 0; + // Called when the native widget is created. // The |desktop_widget| bool is true for widgets created in the desktop and // false for widgets created in the shell. diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index 62b4b56680940..cb801a20a8667 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc @@ -1056,6 +1056,11 @@ void Widget::OnNativeWidgetVisibilityChanged(bool visible) { root->layer()->SetVisible(visible); } +void Widget::OnSoftVisibilityChanged(bool visible) { + if (View* root = GetRootView()) + root->PropagateSoftVisibilityChanged(visible); +} + void Widget::OnNativeWidgetCreated(bool desktop_widget) { if (is_top_level()) focus_manager_.reset(FocusManagerFactory::Create(this, desktop_widget)); diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 0376866fc259e..6821953233f94 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h @@ -791,6 +791,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, void OnNativeBlur() override; void OnNativeWidgetVisibilityChanging(bool visible) override; void OnNativeWidgetVisibilityChanged(bool visible) override; + void OnSoftVisibilityChanged(bool visible) override; void OnNativeWidgetCreated(bool desktop_widget) override; void OnNativeWidgetDestroying() override; void OnNativeWidgetDestroyed() override; diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index b035fd32716f7..65cd1aab424fa 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc @@ -2404,8 +2404,14 @@ void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) { void HWNDMessageHandler::OnSessionChange(WPARAM status_code) { // Direct3D presents are ignored while the screen is locked, so force the // window to be redrawn on unlock. - if (status_code == WTS_SESSION_UNLOCK) + if (status_code == WTS_SESSION_UNLOCK) { ForceRedrawWindow(10); + if (IsVisible()) + delegate_->HandleSoftVisibilityChanged(true); + } else if (status_code == WTS_SESSION_LOCK) { + if (IsVisible()) + delegate_->HandleSoftVisibilityChanged(false); + } } void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) { diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h index f9e027d6faa81..cd954adc8b9c2 100644 --- a/ui/views/win/hwnd_message_handler_delegate.h +++ b/ui/views/win/hwnd_message_handler_delegate.h @@ -168,6 +168,12 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate { // Called when the window's visibility changed. |visible| holds the new state. virtual void HandleVisibilityChanged(bool visible) = 0; + // Called when the "calculated" window's visibility changed. + // OS doesn't mark windows hidden on screen lock or when other opaque windows + // cover them. + // |visible| holds the new state. + virtual void HandleSoftVisibilityChanged(bool visible) = 0; + // Called when the window's client size changed. |new_size| holds the new // size. virtual void HandleClientSizeChanged(const gfx::Size& new_size) = 0;