Backed out 5 changesets (bug 1672493) for causing process-crashes @ @ mozilla::Thread...
[gecko.git] / widget / windows / WinWindowOcclusionTracker.h
blob3b44a132c493ac2f600e01664ee926bf4cce6ff2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef widget_windows_WinWindowOcclusionTracker_h
8 #define widget_windows_WinWindowOcclusionTracker_h
10 #include <windef.h>
12 #include <unordered_map>
13 #include <unordered_set>
14 #include <vector>
16 #include "nsIWeakReferenceUtils.h"
17 #include "mozilla/Monitor.h"
18 #include "mozilla/StaticPtr.h"
19 #include "mozilla/widget/WindowOcclusionState.h"
20 #include "Units.h"
21 #include "nsThreadUtils.h"
23 class nsBaseWidget;
24 struct IVirtualDesktopManager;
25 class WinWindowOcclusionTrackerTest;
26 class WinWindowOcclusionTrackerInteractiveTest;
28 namespace base {
29 class Thread;
30 } // namespace base
32 namespace mozilla {
34 namespace widget {
36 class OcclusionUpdateRunnable;
37 class SerializedTaskDispatcher;
38 class UpdateOcclusionStateRunnable;
40 // This class handles window occlusion tracking by using HWND.
41 // Implementation is borrowed from chromium's NativeWindowOcclusionTrackerWin.
42 class WinWindowOcclusionTracker final {
43 public:
44 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WinWindowOcclusionTracker)
46 /// Can only be called from the main thread.
47 static WinWindowOcclusionTracker* Get();
49 /// Can only be called from the main thread.
50 static void Ensure();
52 /// Can only be called from the main thread.
53 static void ShutDown();
55 /// Can be called from any thread.
56 static MessageLoop* OcclusionCalculatorLoop();
58 /// Can be called from any thread.
59 static bool IsInWinWindowOcclusionThread();
61 // Enables notifying to widget via NotifyOcclusionState() when the occlusion
62 // state has been computed.
63 void Enable(nsBaseWidget* aWindow, HWND aHwnd);
65 // Disables notifying to widget via NotifyOcclusionState() when the occlusion
66 // state has been computed.
67 void Disable(nsBaseWidget* aWindow, HWND aHwnd);
69 // Called when widget's visibility is changed
70 void OnWindowVisibilityChanged(nsBaseWidget* aWindow, bool aVisible);
72 SerializedTaskDispatcher* GetSerializedTaskDispatcher() {
73 return mSerializedTaskDispatcher;
76 void TriggerCalculation();
78 void DumpOccludingWindows(HWND aHWnd);
80 private:
81 friend class ::WinWindowOcclusionTrackerTest;
82 friend class ::WinWindowOcclusionTrackerInteractiveTest;
84 explicit WinWindowOcclusionTracker(UniquePtr<base::Thread> aThread);
85 virtual ~WinWindowOcclusionTracker();
87 // This class computes the occlusion state of the tracked windows.
88 // It runs on a separate thread, and notifies the main thread of
89 // the occlusion state of the tracked windows.
90 class WindowOcclusionCalculator {
91 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WindowOcclusionCalculator)
92 public:
93 // Creates WindowOcclusionCalculator instance.
94 static void CreateInstance();
96 // Clear WindowOcclusionCalculator instance.
97 static void ClearInstance();
99 // Returns existing WindowOcclusionCalculator instance.
100 static WindowOcclusionCalculator* GetInstance() { return sCalculator; }
102 void Initialize();
103 void Shutdown();
105 void EnableOcclusionTrackingForWindow(HWND hwnd);
106 void DisableOcclusionTrackingForWindow(HWND hwnd);
108 // If a window becomes visible, makes sure event hooks are registered.
109 void HandleVisibilityChanged(bool aVisible);
111 void HandleTriggerCalculation();
113 private:
114 WindowOcclusionCalculator();
115 ~WindowOcclusionCalculator();
117 // Registers event hooks, if not registered.
118 void MaybeRegisterEventHooks();
120 // This is the callback registered to get notified of various Windows
121 // events, like window moving/resizing.
122 static void CALLBACK EventHookCallback(HWINEVENTHOOK aWinEventHook,
123 DWORD aEvent, HWND aHwnd,
124 LONG aIdObject, LONG aIdChild,
125 DWORD aEventThread,
126 DWORD aMsEventTime);
128 // EnumWindows callback used to iterate over all hwnds to determine
129 // occlusion status of all tracked root windows. Also builds up
130 // |current_pids_with_visible_windows_| and registers event hooks for newly
131 // discovered processes with visible hwnds.
132 static BOOL CALLBACK
133 ComputeNativeWindowOcclusionStatusCallback(HWND hwnd, LPARAM lParam);
135 // EnumWindows callback used to update the list of process ids with
136 // visible hwnds, |pids_for_location_change_hook_|.
137 static BOOL CALLBACK UpdateVisibleWindowProcessIdsCallback(HWND aHwnd,
138 LPARAM aLParam);
140 // Determines which processes owning visible application windows to set the
141 // EVENT_OBJECT_LOCATIONCHANGE event hook for and stores the pids in
142 // |pids_for_location_change_hook_|.
143 void UpdateVisibleWindowProcessIds();
145 // Computes the native window occlusion status for all tracked root gecko
146 // windows in |root_window_hwnds_occlusion_state_| and notifies them if
147 // their occlusion status has changed.
148 void ComputeNativeWindowOcclusionStatus();
150 // Schedules an occlusion calculation , if one isn't already scheduled.
151 void ScheduleOcclusionCalculationIfNeeded();
153 // Registers a global event hook (not per process) for the events in the
154 // range from |event_min| to |event_max|, inclusive.
155 void RegisterGlobalEventHook(DWORD aEventMin, DWORD aEventMax);
157 // Registers the EVENT_OBJECT_LOCATIONCHANGE event hook for the process with
158 // passed id. The process has one or more visible, opaque windows.
159 void RegisterEventHookForProcess(DWORD aPid);
161 // Registers/Unregisters the event hooks necessary for occlusion tracking
162 // via calls to RegisterEventHook. These event hooks are disabled when all
163 // tracked windows are minimized.
164 void RegisterEventHooks();
165 void UnregisterEventHooks();
167 // EnumWindows callback for occlusion calculation. Returns true to
168 // continue enumeration, false otherwise. Currently, always returns
169 // true because this function also updates currentPidsWithVisibleWindows,
170 // and needs to see all HWNDs.
171 bool ProcessComputeNativeWindowOcclusionStatusCallback(
172 HWND aHwnd, std::unordered_set<DWORD>* aCurrentPidsWithVisibleWindows);
174 // Processes events sent to OcclusionEventHookCallback.
175 // It generally triggers scheduling of the occlusion calculation, but
176 // ignores certain events in order to not calculate occlusion more than
177 // necessary.
178 void ProcessEventHookCallback(HWINEVENTHOOK aWinEventHook, DWORD aEvent,
179 HWND aHwnd, LONG aIdObject, LONG aIdChild);
181 // EnumWindows callback for determining which processes to set the
182 // EVENT_OBJECT_LOCATIONCHANGE event hook for. We set that event hook for
183 // processes hosting fully visible, opaque windows.
184 void ProcessUpdateVisibleWindowProcessIdsCallback(HWND aHwnd);
186 // Returns true if the window is visible, fully opaque, and on the current
187 // virtual desktop, false otherwise.
188 bool WindowCanOccludeOtherWindowsOnCurrentVirtualDesktop(
189 HWND aHwnd, LayoutDeviceIntRect* aWindowRect);
191 // Returns true if aHwnd is definitely on the current virtual desktop,
192 // false if it's definitely not on the current virtual desktop, and Nothing
193 // if we we can't tell for sure.
194 Maybe<bool> IsWindowOnCurrentVirtualDesktop(HWND aHwnd);
196 static StaticRefPtr<WindowOcclusionCalculator> sCalculator;
198 // Map of root app window hwnds and their occlusion state. This contains
199 // both visible and hidden windows.
200 // It is accessed from WinWindowOcclusionTracker::UpdateOcclusionState()
201 // without using mutex. The access is safe by using
202 // SerializedTaskDispatcher.
203 std::unordered_map<HWND, OcclusionState> mRootWindowHwndsOcclusionState;
205 // Values returned by SetWinEventHook are stored so that hooks can be
206 // unregistered when necessary.
207 std::vector<HWINEVENTHOOK> mGlobalEventHooks;
209 // Map from process id to EVENT_OBJECT_LOCATIONCHANGE event hook.
210 std::unordered_map<DWORD, HWINEVENTHOOK> mProcessEventHooks;
212 // Pids of processes for which the EVENT_OBJECT_LOCATIONCHANGE event hook is
213 // set.
214 std::unordered_set<DWORD> mPidsForLocationChangeHook;
216 // Used as a timer to delay occlusion update.
217 RefPtr<CancelableRunnable> mOcclusionUpdateRunnable;
219 // Used to determine if a window is occluded. As we iterate through the
220 // hwnds in z-order, we subtract each opaque window's rect from
221 // mUnoccludedDesktopRegion. When we get to a root window, we subtract
222 // it from mUnoccludedDesktopRegion, and if mUnoccludedDesktopRegion
223 // doesn't change, the root window was already occluded.
224 LayoutDeviceIntRegion mUnoccludedDesktopRegion;
226 // Keeps track of how many root windows we need to compute the occlusion
227 // state of in a call to ComputeNativeWindowOcclusionStatus. Once we've
228 // determined the state of all root windows, we can stop subtracting
229 // windows from mUnoccludedDesktopRegion;.
230 int mNumRootWindowsWithUnknownOcclusionState;
232 // This is true if the task bar thumbnails or the alt tab thumbnails are
233 // showing.
234 bool mShowingThumbnails = false;
236 // Used to keep track of the window that's currently moving. That window
237 // is ignored for calculation occlusion so that tab dragging won't
238 // ignore windows occluded by the dragged window.
239 HWND mMovingWindow = 0;
241 // Only used on Win10+.
242 RefPtr<IVirtualDesktopManager> mVirtualDesktopManager;
244 // Used to serialize tasks related to mRootWindowHwndsOcclusionState.
245 RefPtr<SerializedTaskDispatcher> mSerializedTaskDispatcher;
247 // This is an alias to the singleton WinWindowOcclusionTracker mMonitor,
248 // and is used in ShutDown().
249 Monitor& mMonitor;
251 friend class OcclusionUpdateRunnable;
254 static BOOL CALLBACK DumpOccludingWindowsCallback(HWND aHWnd, LPARAM aLParam);
256 // Returns true if we are interested in |hwnd| for purposes of occlusion
257 // calculation. We are interested in |hwnd| if it is a window that is
258 // visible, opaque, bounded, and not a popup or floating window. If we are
259 // interested in |hwnd|, stores the window rectangle in |window_rect|.
260 static bool IsWindowVisibleAndFullyOpaque(HWND aHwnd,
261 LayoutDeviceIntRect* aWindowRect);
263 void Destroy();
265 static void CallUpdateOcclusionState(
266 std::unordered_map<HWND, OcclusionState>* aMap, bool aShowAllWindows);
268 // Updates root windows occclusion state. If aShowAllWindows is true,
269 // all non-hidden windows will be marked visible. This is used to force
270 // rendering of thumbnails.
271 void UpdateOcclusionState(std::unordered_map<HWND, OcclusionState>* aMap,
272 bool aShowAllWindows);
274 public:
275 // This is called with session changed notifications. If the screen is locked
276 // by the current session, it marks app windows as occluded.
277 void OnSessionChange(WPARAM aStatusCode);
279 // This is called when the display is put to sleep. If the display is sleeping
280 // it marks app windows as occluded.
281 void OnDisplayStateChanged(bool aDisplayOn);
283 private:
284 // Marks all root windows as either occluded, or if hwnd IsIconic, hidden.
285 void MarkNonIconicWindowsOccluded();
287 static StaticRefPtr<WinWindowOcclusionTracker> sTracker;
289 // "WinWindowOcclusionCalc" thread.
290 UniquePtr<base::Thread> mThread;
291 Monitor mMonitor;
293 // Has ShutDown been called on us? We might have survived if our thread join
294 // timed out.
295 bool mHasAttemptedShutdown = false;
297 // Map of HWND to widget. Maintained on main thread, and used to send
298 // occlusion state notifications to Windows from
299 // mRootWindowHwndsOcclusionState.
300 std::unordered_map<HWND, nsWeakPtr> mHwndRootWindowMap;
302 // This is set by UpdateOcclusionState(). It is currently only used by tests.
303 int mNumVisibleRootWindows = 0;
305 // If the screen is locked, windows are considered occluded.
306 bool mScreenLocked = false;
308 // If the display is off, windows are considered occluded.
309 bool mDisplayOn = true;
311 // Used to serialize tasks related to mRootWindowHwndsOcclusionState.
312 RefPtr<SerializedTaskDispatcher> mSerializedTaskDispatcher;
314 friend class OcclusionUpdateRunnable;
315 friend class UpdateOcclusionStateRunnable;
318 } // namespace widget
319 } // namespace mozilla
321 #endif // widget_windows_WinWindowOcclusionTracker_h