Commit c90084e3 authored by David Bienvenu's avatar David Bienvenu Committed by Commit Bot

Support windows virtual desktops in occlusion calculation.

If a browser window is not on the current virtual desktop, it is marked occluded.
If a window is not on the current virtual desktop, we ignore it when deciding if
a browser window is occluded or not.

This unfortunately spams the VS output window - newer versions of Windows have fixed this.

Bug: 943534
Change-Id: Iee9654f494fb2f977688c93347f4171447fb4b58
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1531460Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Commit-Queue: David Bienvenu <davidbienvenu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#643347}
parent 52a558e7
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/win/scoped_gdi_object.h" #include "base/win/scoped_gdi_object.h"
#include "base/win/windows_version.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
namespace aura { namespace aura {
...@@ -118,7 +119,7 @@ NativeWindowOcclusionTrackerWin::~NativeWindowOcclusionTrackerWin() { ...@@ -118,7 +119,7 @@ NativeWindowOcclusionTrackerWin::~NativeWindowOcclusionTrackerWin() {
bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque( bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
HWND hwnd, HWND hwnd,
gfx::Rect* window_rect) { gfx::Rect* window_rect) {
// Filter out windows that are not “visible”, IsWindowVisible(). // Filter out windows that are not "visible", IsWindowVisible().
if (!IsWindow(hwnd) || !IsWindowVisible(hwnd)) if (!IsWindow(hwnd) || !IsWindowVisible(hwnd))
return false; return false;
...@@ -128,12 +129,12 @@ bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque( ...@@ -128,12 +129,12 @@ bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE); LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
// Filter out “transparent” windows, windows where the mouse clicks fall // Filter out "transparent" windows, windows where the mouse clicks fall
// through them. // through them.
if (ex_styles & WS_EX_TRANSPARENT) if (ex_styles & WS_EX_TRANSPARENT)
return false; return false;
// Filter out “tool windows”, which are floating windows that do not appear on // Filter out "tool windows", which are floating windows that do not appear on
// the taskbar or ALT-TAB. Floating windows can have larger window rectangles // the taskbar or ALT-TAB. Floating windows can have larger window rectangles
// than what is visible to the user, so by filtering them out we will avoid // than what is visible to the user, so by filtering them out we will avoid
// incorrectly marking native windows as occluded. // incorrectly marking native windows as occluded.
...@@ -219,6 +220,11 @@ NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator:: ...@@ -219,6 +220,11 @@ NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner) scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner)
: task_runner_(task_runner), ui_thread_task_runner_(ui_thread_task_runner) { : task_runner_(task_runner), ui_thread_task_runner_(ui_thread_task_runner) {
if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
CHECK(SUCCEEDED(
::CoCreateInstance(__uuidof(VirtualDesktopManager), nullptr, CLSCTX_ALL,
IID_PPV_ARGS(&virtual_desktop_manager_))));
}
DETACH_FROM_SEQUENCE(sequence_checker_); DETACH_FROM_SEQUENCE(sequence_checker_);
} }
...@@ -313,7 +319,7 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator:: ...@@ -313,7 +319,7 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
if (root_window_hwnds_occlusion_state_.empty()) if (root_window_hwnds_occlusion_state_.empty())
return; return;
// Set up initial conditions for occlusion calculation. // Set up initial conditions for occlusion calculation.
bool all_minimized = true; bool should_unregister_event_hooks = true;
// Compute the SkRegion for the screen. // Compute the SkRegion for the screen.
int screen_left = GetSystemMetrics(SM_XVIRTUALSCREEN); int screen_left = GetSystemMetrics(SM_XVIRTUALSCREEN);
...@@ -331,6 +337,14 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator:: ...@@ -331,6 +337,14 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
// minimized windows to HIDDEN. // minimized windows to HIDDEN.
if (IsIconic(hwnd)) { if (IsIconic(hwnd)) {
root_window_pair.second.occlusion_state = Window::OcclusionState::HIDDEN; root_window_pair.second.occlusion_state = Window::OcclusionState::HIDDEN;
} else if (IsWindowOnCurrentVirtualDesktop(hwnd) == false) {
// If window is not on the current virtual desktop, immediately
// set the state of the window to OCCLUDED.
root_window_pair.second.occlusion_state =
Window::OcclusionState::OCCLUDED;
// Don't unregister event hooks when not on current desktop. There's no
// notification when that changes, so we can't reregister event hooks.
should_unregister_event_hooks = false;
} else { } else {
root_window_pair.second.occlusion_state = Window::OcclusionState::UNKNOWN; root_window_pair.second.occlusion_state = Window::OcclusionState::UNKNOWN;
RECT window_rect; RECT window_rect;
...@@ -345,11 +359,11 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator:: ...@@ -345,11 +359,11 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
} }
// If call to GetWindowRect fails, window will be treated as occluded, // If call to GetWindowRect fails, window will be treated as occluded,
// because unoccluded_region will be empty. // because unoccluded_region will be empty.
all_minimized = false; should_unregister_event_hooks = false;
} }
} }
// Unregister event hooks if all native windows are minimized. // Unregister event hooks if all native windows are minimized.
if (all_minimized) { if (should_unregister_event_hooks) {
UnregisterEventHooks(); UnregisterEventHooks();
} else { } else {
base::flat_set<DWORD> current_pids_with_visible_windows; base::flat_set<DWORD> current_pids_with_visible_windows;
...@@ -504,7 +518,7 @@ bool NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator:: ...@@ -504,7 +518,7 @@ bool NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
break; break;
} }
} }
if (!IsWindowVisibleAndFullyOpaque(hwnd, &window_rect)) if (!WindowCanOccludeOtherWindowsOnCurrentVirtualDesktop(hwnd, &window_rect))
return true; return true;
// We are interested in this window, but are not currently hooking it with // We are interested in this window, but are not currently hooking it with
// EVENT_OBJECT_LOCATION_CHANGE, so we need to hook it. We check // EVENT_OBJECT_LOCATION_CHANGE, so we need to hook it. We check
...@@ -585,11 +599,32 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator:: ...@@ -585,11 +599,32 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
ProcessUpdateVisibleWindowProcessIdsCallback(HWND hwnd) { ProcessUpdateVisibleWindowProcessIdsCallback(HWND hwnd) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gfx::Rect window_rect; gfx::Rect window_rect;
if (IsWindowVisibleAndFullyOpaque(hwnd, &window_rect)) { if (WindowCanOccludeOtherWindowsOnCurrentVirtualDesktop(hwnd, &window_rect)) {
DWORD pid; DWORD pid;
GetWindowThreadProcessId(hwnd, &pid); GetWindowThreadProcessId(hwnd, &pid);
pids_for_location_change_hook_.insert(pid); pids_for_location_change_hook_.insert(pid);
} }
} }
bool NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
WindowCanOccludeOtherWindowsOnCurrentVirtualDesktop(
HWND hwnd,
gfx::Rect* window_rect) {
return IsWindowVisibleAndFullyOpaque(hwnd, window_rect) &&
(IsWindowOnCurrentVirtualDesktop(hwnd) == true);
}
base::Optional<bool> NativeWindowOcclusionTrackerWin::
WindowOcclusionCalculator::IsWindowOnCurrentVirtualDesktop(HWND hwnd) {
if (virtual_desktop_manager_) {
BOOL on_current_desktop;
if (SUCCEEDED(virtual_desktop_manager_->IsWindowOnCurrentVirtualDesktop(
hwnd, &on_current_desktop))) {
return on_current_desktop;
}
}
return base::nullopt;
}
} // namespace aura } // namespace aura
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#ifndef UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_ #ifndef UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
#define UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_ #define UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
#include <shobjidl.h>
#include <windows.h> #include <windows.h>
#include <winuser.h> #include <winuser.h>
#include <wrl/client.h>
#include <memory> #include <memory>
#include <vector> #include <vector>
...@@ -151,6 +153,17 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver { ...@@ -151,6 +153,17 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
// processes hosting fully visible, opaque windows. // processes hosting fully visible, opaque windows.
void ProcessUpdateVisibleWindowProcessIdsCallback(HWND hwnd); void ProcessUpdateVisibleWindowProcessIdsCallback(HWND hwnd);
// Returns true if the window is visible, fully opaque, and on the current
// virtual desktop, false otherwise.
bool WindowCanOccludeOtherWindowsOnCurrentVirtualDesktop(
HWND hwnd,
gfx::Rect* window_rect);
// Returns true if |hwnd| is definitely on the current virtual desktop,
// false if it's definitely not on the current virtual desktop, and nullopt
// if we we can't tell for sure.
base::Optional<bool> IsWindowOnCurrentVirtualDesktop(HWND hwnd);
// Task runner for our thread. // Task runner for our thread.
scoped_refptr<base::SequencedTaskRunner> task_runner_; scoped_refptr<base::SequencedTaskRunner> task_runner_;
...@@ -183,6 +196,9 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver { ...@@ -183,6 +196,9 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
// calculating window occlusion. // calculating window occlusion.
bool window_is_moving_ = false; bool window_is_moving_ = false;
// Only used on Win10+.
Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionCalculator); DISALLOW_COPY_AND_ASSIGN(WindowOcclusionCalculator);
...@@ -192,9 +208,9 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver { ...@@ -192,9 +208,9 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
~NativeWindowOcclusionTrackerWin() override; ~NativeWindowOcclusionTrackerWin() override;
// Returns true if we are interested in |hwnd| for purposes of occlusion // Returns true if we are interested in |hwnd| for purposes of occlusion
// calculation. We are interested in |hwnd| if it is a window that is visible, // calculation. We are interested in |hwnd| if it is a window that is
// opaque, and bounded. If we are interested in |hwnd|, stores the window // visible, opaque, and bounded. If we are interested in |hwnd|, stores the
// rectangle in |window_rect|. // window rectangle in |window_rect|.
static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect); static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect);
// Updates root windows occclusion state. // Updates root windows occclusion state.
......
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