Commit d2852ba3 authored by Chris Davis (EDGE)'s avatar Chris Davis (EDGE) Committed by Commit Bot

Add listener for display sleeping to window occlusion feature

This change adds a listener for power state change
GUID_SESSION_DISPLAY_STATUS which is triggered when the display
is put to sleep.  We can then treat it as an occlusion case to
save battery.

Bug: 1137910
Change-Id: Id28d6b2b14c982356f859d3116e65951569965b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2487069Reviewed-by: default avatarDavid Bienvenu <davidbienvenu@chromium.org>
Reviewed-by: default avatarBruce Dawson <brucedawson@chromium.org>
Commit-Queue: Chris Davis <chrdavis@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#820138}
parent 5ca8b53a
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "ui/aura/native_window_occlusion_tracker_win.h" #include "ui/aura/native_window_occlusion_tracker_win.h"
#include <dwmapi.h> #include <dwmapi.h>
#include <powersetting.h>
#include <memory> #include <memory>
#include "base/bind.h" #include "base/bind.h"
...@@ -120,7 +121,8 @@ NativeWindowOcclusionTrackerWin::NativeWindowOcclusionTrackerWin() ...@@ -120,7 +121,8 @@ NativeWindowOcclusionTrackerWin::NativeWindowOcclusionTrackerWin()
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
session_change_observer_( session_change_observer_(
base::BindRepeating(&NativeWindowOcclusionTrackerWin::OnSessionChange, base::BindRepeating(&NativeWindowOcclusionTrackerWin::OnSessionChange,
base::Unretained(this))) { base::Unretained(this))),
power_setting_change_listener_(this) {
WindowOcclusionCalculator::CreateInstance( WindowOcclusionCalculator::CreateInstance(
update_occlusion_task_runner_, base::SequencedTaskRunnerHandle::Get(), update_occlusion_task_runner_, base::SequencedTaskRunnerHandle::Get(),
base::BindRepeating( base::BindRepeating(
...@@ -234,17 +236,18 @@ void NativeWindowOcclusionTrackerWin::UpdateOcclusionState( ...@@ -234,17 +236,18 @@ void NativeWindowOcclusionTrackerWin::UpdateOcclusionState(
continue; continue;
// Check Window::IsVisible here, on the UI thread, because it can't be // Check Window::IsVisible here, on the UI thread, because it can't be
// checked on the occlusion calculation thread. Do this first before // checked on the occlusion calculation thread. Do this first before
// checking screen_locked_ so that hidden windows remain hidden. // checking screen_locked_ or display_on_ so that hidden windows remain
// hidden.
if (!it->second->IsVisible()) { if (!it->second->IsVisible()) {
it->second->GetHost()->SetNativeWindowOcclusionState( it->second->GetHost()->SetNativeWindowOcclusionState(
Window::OcclusionState::HIDDEN); Window::OcclusionState::HIDDEN);
continue; continue;
} }
// If the screen is locked, ignore occlusion state results and // If the screen is locked or off, ignore occlusion state results and
// mark the window as occluded. // mark the window as occluded.
it->second->GetHost()->SetNativeWindowOcclusionState( it->second->GetHost()->SetNativeWindowOcclusionState(
screen_locked_ ? Window::OcclusionState::OCCLUDED screen_locked_ || !display_on_ ? Window::OcclusionState::OCCLUDED
: root_window_pair.second); : root_window_pair.second);
num_visible_root_windows_++; num_visible_root_windows_++;
} }
} }
...@@ -260,14 +263,29 @@ void NativeWindowOcclusionTrackerWin::OnSessionChange( ...@@ -260,14 +263,29 @@ void NativeWindowOcclusionTrackerWin::OnSessionChange(
screen_locked_ = false; screen_locked_ = false;
} else if (status_code == WTS_SESSION_LOCK && is_current_session) { } else if (status_code == WTS_SESSION_LOCK && is_current_session) {
screen_locked_ = true; screen_locked_ = true;
// Set all visible root windows as occluded. If not visible, MarkNonIconicWindowsOccluded();
// set them as hidden. }
for (const auto& root_window_hwnd_pair : hwnd_root_window_map_) { }
root_window_hwnd_pair.second->GetHost()->SetNativeWindowOcclusionState(
IsIconic(root_window_hwnd_pair.first) void NativeWindowOcclusionTrackerWin::OnDisplayStateChanged(bool display_on) {
? Window::OcclusionState::HIDDEN if (display_on == display_on_)
: Window::OcclusionState::OCCLUDED); return;
}
display_on_ = display_on;
// Display changing to on will cause a foreground window change,
// which will trigger an occlusion calculation on its own.
if (!display_on_)
MarkNonIconicWindowsOccluded();
}
void NativeWindowOcclusionTrackerWin::MarkNonIconicWindowsOccluded() {
// Set all visible root windows as occluded. If not visible,
// set them as hidden.
for (const auto& root_window_hwnd_pair : hwnd_root_window_map_) {
root_window_hwnd_pair.second->GetHost()->SetNativeWindowOcclusionState(
IsIconic(root_window_hwnd_pair.first)
? Window::OcclusionState::HIDDEN
: Window::OcclusionState::OCCLUDED);
} }
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "ui/aura/aura_export.h" #include "ui/aura/aura_export.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_observer.h" #include "ui/aura/window_observer.h"
#include "ui/base/win/power_setting_change_listener.h"
#include "ui/base/win/session_change_observer.h" #include "ui/base/win/session_change_observer.h"
namespace base { namespace base {
...@@ -38,7 +39,9 @@ namespace aura { ...@@ -38,7 +39,9 @@ namespace aura {
// This class keeps track of whether any HWNDs are occluding any app windows. // This class keeps track of whether any HWNDs are occluding any app windows.
// It notifies the host of any app window whose occlusion state changes. Most // It notifies the host of any app window whose occlusion state changes. Most
// code should not need to use this; it's an implementation detail. // code should not need to use this; it's an implementation detail.
class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver { class AURA_EXPORT NativeWindowOcclusionTrackerWin
: public WindowObserver,
public ui::PowerSettingChangeListener {
public: public:
static NativeWindowOcclusionTrackerWin* GetOrCreateInstance(); static NativeWindowOcclusionTrackerWin* GetOrCreateInstance();
...@@ -258,6 +261,13 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver { ...@@ -258,6 +261,13 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
// by the current session, it marks app windows as occluded. // by the current session, it marks app windows as occluded.
void OnSessionChange(WPARAM status_code, const bool* is_current_session); void OnSessionChange(WPARAM status_code, const bool* is_current_session);
// This is called when the display is put to sleep. If the display is sleeping
// it marks app windows as occluded.
void OnDisplayStateChanged(bool display_on) override;
// Marks all root windows as either occluded, or if hwnd IsIconic, hidden.
void MarkNonIconicWindowsOccluded();
// Task runner to call ComputeNativeWindowOcclusionStatus, and to handle // Task runner to call ComputeNativeWindowOcclusionStatus, and to handle
// Windows event notifications, off of the UI thread. // Windows event notifications, off of the UI thread.
const scoped_refptr<base::SequencedTaskRunner> update_occlusion_task_runner_; const scoped_refptr<base::SequencedTaskRunner> update_occlusion_task_runner_;
...@@ -273,9 +283,15 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver { ...@@ -273,9 +283,15 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
// Manages observation of Windows Session Change messages. // Manages observation of Windows Session Change messages.
ui::SessionChangeObserver session_change_observer_; ui::SessionChangeObserver session_change_observer_;
// Listens for Power Setting Change messages.
ui::ScopedPowerSettingChangeListener power_setting_change_listener_;
// If the screen is locked, windows are considered occluded. // If the screen is locked, windows are considered occluded.
bool screen_locked_ = false; bool screen_locked_ = false;
// If the display is off, windows are considered occluded.
bool display_on_ = true;
base::WeakPtrFactory<NativeWindowOcclusionTrackerWin> weak_factory_{this}; base::WeakPtrFactory<NativeWindowOcclusionTrackerWin> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerWin); DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerWin);
......
...@@ -221,6 +221,8 @@ component("base") { ...@@ -221,6 +221,8 @@ component("base") {
"win/message_box_win.h", "win/message_box_win.h",
"win/mouse_wheel_util.cc", "win/mouse_wheel_util.cc",
"win/mouse_wheel_util.h", "win/mouse_wheel_util.h",
"win/power_setting_change_listener.cc",
"win/power_setting_change_listener.h",
"win/scoped_ole_initializer.cc", "win/scoped_ole_initializer.cc",
"win/scoped_ole_initializer.h", "win/scoped_ole_initializer.h",
"win/session_change_observer.cc", "win/session_change_observer.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/win/power_setting_change_listener.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "ui/gfx/win/singleton_hwnd.h"
#include "ui/gfx/win/singleton_hwnd_observer.h"
namespace ui {
class PowerSettingChangeObserver {
public:
static PowerSettingChangeObserver* GetInstance();
void AddListener(PowerSettingChangeListener* listener);
void RemoveListener(PowerSettingChangeListener* listener);
private:
friend struct base::DefaultSingletonTraits<PowerSettingChangeObserver>;
PowerSettingChangeObserver();
virtual ~PowerSettingChangeObserver();
void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
void OnDisplayStateChanged(bool display_on);
static HPOWERNOTIFY RegisterNotification(LPCGUID power_setting);
static BOOL UnregisterNotification(HPOWERNOTIFY handle);
base::ObserverList<PowerSettingChangeListener>::Unchecked listeners_;
std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
HPOWERNOTIFY power_display_state_;
};
// static
PowerSettingChangeObserver* PowerSettingChangeObserver::GetInstance() {
return base::Singleton<PowerSettingChangeObserver>::get();
}
PowerSettingChangeObserver::PowerSettingChangeObserver()
: singleton_hwnd_observer_(new gfx::SingletonHwndObserver(
base::BindRepeating(&PowerSettingChangeObserver::OnWndProc,
base::Unretained(this)))),
power_display_state_(RegisterNotification(&GUID_SESSION_DISPLAY_STATUS)) {
}
PowerSettingChangeObserver::~PowerSettingChangeObserver() {
UnregisterNotification(power_display_state_);
}
void PowerSettingChangeObserver::AddListener(
PowerSettingChangeListener* listener) {
listeners_.AddObserver(listener);
}
void PowerSettingChangeObserver::RemoveListener(
PowerSettingChangeListener* listener) {
listeners_.RemoveObserver(listener);
}
void PowerSettingChangeObserver::OnWndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
if (message == WM_POWERBROADCAST && wparam == PBT_POWERSETTINGCHANGE) {
POWERBROADCAST_SETTING* setting = (POWERBROADCAST_SETTING*)lparam;
if (setting &&
IsEqualGUID(setting->PowerSetting, GUID_SESSION_DISPLAY_STATUS) &&
setting->DataLength == sizeof(DWORD)) {
OnDisplayStateChanged(
PowerMonitorOff !=
static_cast<MONITOR_DISPLAY_STATE>(setting->Data[0]));
}
}
}
void PowerSettingChangeObserver::OnDisplayStateChanged(bool display_on) {
for (PowerSettingChangeListener& observer : listeners_)
observer.OnDisplayStateChanged(display_on);
}
HPOWERNOTIFY PowerSettingChangeObserver::RegisterNotification(
LPCGUID power_setting) {
return RegisterPowerSettingNotification(
gfx::SingletonHwnd::GetInstance()->hwnd(), power_setting,
DEVICE_NOTIFY_WINDOW_HANDLE);
}
BOOL PowerSettingChangeObserver::UnregisterNotification(HPOWERNOTIFY handle) {
return UnregisterPowerSettingNotification(handle);
}
ScopedPowerSettingChangeListener::ScopedPowerSettingChangeListener(
PowerSettingChangeListener* listener)
: listener_(listener) {
PowerSettingChangeObserver::GetInstance()->AddListener(listener_);
}
ScopedPowerSettingChangeListener::~ScopedPowerSettingChangeListener() {
PowerSettingChangeObserver::GetInstance()->RemoveListener(listener_);
}
} // namespace ui
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_WIN_POWER_SETTING_CHANGE_LISTENER_H_
#define UI_BASE_WIN_POWER_SETTING_CHANGE_LISTENER_H_
#include "base/component_export.h"
namespace ui {
// Interface for classes that want to listen to power setting changes.
class COMPONENT_EXPORT(UI_BASE) PowerSettingChangeListener {
public:
virtual void OnDisplayStateChanged(bool display_on) = 0;
protected:
virtual ~PowerSettingChangeListener() = default;
};
// Create an instance of this class in any object that wants to listen
// for power setting changes.
class COMPONENT_EXPORT(UI_BASE) ScopedPowerSettingChangeListener {
public:
explicit ScopedPowerSettingChangeListener(
PowerSettingChangeListener* listener);
~ScopedPowerSettingChangeListener();
private:
PowerSettingChangeListener* listener_;
ScopedPowerSettingChangeListener(const ScopedPowerSettingChangeListener&) =
delete;
const ScopedPowerSettingChangeListener& operator=(
const ScopedPowerSettingChangeListener&) = delete;
};
} // namespace ui
#endif // UI_BASE_WIN_POWER_SETTING_CHANGE_LISTENER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment