forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
native_window_occlusion_tracker_win.h
249 lines (195 loc) · 10.3 KB
/
native_window_occlusion_tracker_win.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Copyright 2018 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_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
#define UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
#include <shobjidl.h>
#include <windows.h>
#include <winuser.h>
#include <wrl/client.h>
#include <memory>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/win/session_change_observer.h"
namespace aura {
// 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
// code should not need to use this; it's an implementation detail.
class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
public:
static NativeWindowOcclusionTrackerWin* GetOrCreateInstance();
// Enables notifying the host of |window| via SetNativeWindowOcclusionState()
// when the occlusion state has been computed.
void Enable(Window* window);
// Disables notifying the host of |window| via
// OnNativeWindowOcclusionStateChanged() when the occlusion state has been
// computed. It's not neccesary to call this when |window| is deleted because
// OnWindowDestroying calls Disable.
void Disable(Window* window);
// aura::WindowObserver:
void OnWindowVisibilityChanged(Window* window, bool visible) override;
void OnWindowDestroying(Window* window) override;
private:
friend class NativeWindowOcclusionTrackerTest;
// This class computes the occlusion state of the tracked windows.
// It runs on a separate thread, and notifies the main thread of
// the occlusion state of the tracked windows.
class WindowOcclusionCalculator {
public:
WindowOcclusionCalculator(
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner);
~WindowOcclusionCalculator();
void EnableOcclusionTrackingForWindow(HWND hwnd);
void DisableOcclusionTrackingForWindow(HWND hwnd);
// If a window becomes visible, makes sure event hooks are registered.
void HandleVisibilityChanged(bool visible);
private:
friend class NativeWindowOcclusionTrackerTest;
struct NativeWindowOcclusionState {
// The region of the native window that is not occluded by other windows.
SkRegion unoccluded_region;
// The current occlusion state of the native window. Default to UNKNOWN
// because we do not know the state starting out. More information on
// these states can be found in aura::Window.
aura::Window::OcclusionState occlusion_state =
aura::Window::OcclusionState::UNKNOWN;
};
// Registers event hooks, if not registered.
void MaybeRegisterEventHooks();
// This is the callback registered to get notified of various Windows
// events, like window moving/resizing.
static void CALLBACK EventHookCallback(HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG id_object,
LONG id_child,
DWORD dwEventThread,
DWORD dwmsEventTime);
// EnumWindows callback used to iterate over all hwnds to determine
// occlusion status of all tracked root windows. Also builds up
// |current_pids_with_visible_windows_| and registers event hooks for newly
// discovered processes with visible hwnds.
static BOOL CALLBACK
ComputeNativeWindowOcclusionStatusCallback(HWND hwnd, LPARAM lParam);
// EnumWindows callback used to update the list of process ids with
// visible hwnds, |pids_for_location_change_hook_|.
static BOOL CALLBACK UpdateVisibleWindowProcessIdsCallback(HWND hwnd,
LPARAM lParam);
// Determines which processes owning visible application windows to set the
// EVENT_OBJECT_LOCATIONCHANGE event hook for and stores the pids in
// |pids_for_location_change_hook_|.
void UpdateVisibleWindowProcessIds();
// Computes the native window occlusion status for all tracked root aura
// windows in |root_window_hwnds_occlusion_state_| and notifies them if
// their occlusion status has changed.
void ComputeNativeWindowOcclusionStatus();
// Schedules an occlusion calculation |update_occlusion_delay_| time in the
// future, if one isn't already scheduled.
void ScheduleOcclusionCalculationIfNeeded();
// Registers a global event hook (not per process) for the events in the
// range from |event_min| to |event_max|, inclusive.
void RegisterGlobalEventHook(UINT event_min, UINT event_max);
// Registers the EVENT_OBJECT_LOCATIONCHANGE event hook for the process with
// passed id. The process has one or more visible, opaque windows.
void RegisterEventHookForProcess(DWORD pid);
// Registers/Unregisters the event hooks necessary for occlusion tracking
// via calls to RegisterEventHook. These event hooks are disabled when all
// tracked windows are minimized.
void RegisterEventHooks();
void UnregisterEventHooks();
// EnumWindows callback for occlusion calculation. Returns true to
// continue enumeration, false otherwise. Currently, always returns
// true because this function also updates
// |current_pids_with_visible_windows|, and needs to see all HWNDs.
bool ProcessComputeNativeWindowOcclusionStatusCallback(
HWND hwnd,
base::flat_set<DWORD>* current_pids_with_visible_windows);
// Processes events sent to OcclusionEventHookCallback.
// It generally triggers scheduling of the occlusion calculation, but
// ignores certain events in order to not calculate occlusion more than
// necessary.
void ProcessEventHookCallback(DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild);
// EnumWindows callback for determining which processes to set the
// EVENT_OBJECT_LOCATIONCHANGE event hook for. We set that event hook for
// processes hosting fully visible, opaque windows.
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.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Task runner for the thread that created |this|. UpdateOcclusionState
// task is posted to this task runner.
const scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner_;
// Map of root app window hwnds and their occlusion state. This contains
// both visible and hidden windows.
base::flat_map<HWND, NativeWindowOcclusionState>
root_window_hwnds_occlusion_state_;
// Values returned by SetWinEventHook are stored so that hooks can be
// unregistered when necessary.
std::vector<HWINEVENTHOOK> global_event_hooks_;
// Map from process id to EVENT_OBJECT_LOCATIONCHANGE event hook.
base::flat_map<DWORD, HWINEVENTHOOK> process_event_hooks_;
// Pids of processes for which the EVENT_OBJECT_LOCATIONCHANGE event hook is
// set. These are the processes hosting windows in
// |visible_and_fully_opaque_windows_|.
base::flat_set<DWORD> pids_for_location_change_hook_;
// Timer to delay occlusion update.
base::OneShotTimer occlusion_update_timer_;
// Used to keep track of whether we're in the middle of getting window move
// events, in order to wait until the window move is complete before
// calculating window occlusion.
bool window_is_moving_ = false;
// Only used on Win10+.
Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionCalculator);
};
NativeWindowOcclusionTrackerWin();
~NativeWindowOcclusionTrackerWin() override;
// 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, opaque, and bounded. If we are interested in |hwnd|, stores the
// window rectangle in |window_rect|.
static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect);
// Updates root windows occclusion state.
void UpdateOcclusionState(const base::flat_map<HWND, Window::OcclusionState>&
root_window_hwnds_occlusion_state);
// This is called with session changed notifications. If the screen is locked,
// it marks app windows as occluded.
void OnSessionChange(WPARAM status_code);
// Task runner to call ComputeNativeWindowOcclusionStatus, and to handle
// Windows event notifications, off of the UI thread.
const scoped_refptr<base::SequencedTaskRunner> update_occlusion_task_runner_;
// Map of HWND to root app windows. Maintained on the UI thread, and used
// to send occlusion state notifications to Windows from
// |root_window_hwnds_occlusion_state_|.
base::flat_map<HWND, Window*> hwnd_root_window_map_;
// This is set by UpdateOcclusionState. It is currently only used by tests.
int num_visible_root_windows_ = 0;
std::unique_ptr<WindowOcclusionCalculator> occlusion_calculator_;
// Manages observation of Windows Session Change messages.
ui::SessionChangeObserver session_change_observer_;
// If the screen is locked, windows are considered occluded.
bool screen_locked_ = false;
DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerWin);
};
} // namespace aura
#endif // UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_