|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* |
|
6 * Windows widget support for event loop instrumentation. |
|
7 * See toolkit/xre/EventTracer.cpp for more details. |
|
8 */ |
|
9 |
|
10 #include <stdio.h> |
|
11 #include <windows.h> |
|
12 |
|
13 #include "mozilla/WidgetTraceEvent.h" |
|
14 #include "nsAppShellCID.h" |
|
15 #include "nsComponentManagerUtils.h" |
|
16 #include "nsCOMPtr.h" |
|
17 #include "nsIAppShellService.h" |
|
18 #include "nsIBaseWindow.h" |
|
19 #include "nsIDocShell.h" |
|
20 #include "nsISupportsImpl.h" |
|
21 #include "nsIWidget.h" |
|
22 #include "nsIXULWindow.h" |
|
23 #include "nsAutoPtr.h" |
|
24 #include "nsServiceManagerUtils.h" |
|
25 #include "nsThreadUtils.h" |
|
26 #include "nsWindowDefs.h" |
|
27 |
|
28 namespace { |
|
29 |
|
30 // Used for signaling the background thread from the main thread. |
|
31 HANDLE sEventHandle = nullptr; |
|
32 |
|
33 // We need a runnable in order to find the hidden window on the main |
|
34 // thread. |
|
35 class HWNDGetter : public nsRunnable { |
|
36 public: |
|
37 HWNDGetter() : hidden_window_hwnd(nullptr) { |
|
38 MOZ_COUNT_CTOR(HWNDGetter); |
|
39 } |
|
40 ~HWNDGetter() { |
|
41 MOZ_COUNT_DTOR(HWNDGetter); |
|
42 } |
|
43 |
|
44 HWND hidden_window_hwnd; |
|
45 |
|
46 NS_IMETHOD Run() { |
|
47 // Jump through some hoops to locate the hidden window. |
|
48 nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); |
|
49 nsCOMPtr<nsIXULWindow> hiddenWindow; |
|
50 |
|
51 nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); |
|
52 if (NS_FAILED(rv)) { |
|
53 return rv; |
|
54 } |
|
55 |
|
56 nsCOMPtr<nsIDocShell> docShell; |
|
57 rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell)); |
|
58 if (NS_FAILED(rv) || !docShell) { |
|
59 return rv; |
|
60 } |
|
61 |
|
62 nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell)); |
|
63 |
|
64 if (!baseWindow) |
|
65 return NS_ERROR_FAILURE; |
|
66 |
|
67 nsCOMPtr<nsIWidget> widget; |
|
68 baseWindow->GetMainWidget(getter_AddRefs(widget)); |
|
69 |
|
70 if (!widget) |
|
71 return NS_ERROR_FAILURE; |
|
72 |
|
73 hidden_window_hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW); |
|
74 |
|
75 return NS_OK; |
|
76 } |
|
77 }; |
|
78 |
|
79 HWND GetHiddenWindowHWND() |
|
80 { |
|
81 // Need to dispatch this to the main thread because plenty of |
|
82 // the things it wants to access are main-thread-only. |
|
83 nsRefPtr<HWNDGetter> getter = new HWNDGetter(); |
|
84 NS_DispatchToMainThread(getter, NS_DISPATCH_SYNC); |
|
85 return getter->hidden_window_hwnd; |
|
86 } |
|
87 |
|
88 } // namespace |
|
89 |
|
90 namespace mozilla { |
|
91 |
|
92 bool InitWidgetTracing() |
|
93 { |
|
94 sEventHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); |
|
95 return sEventHandle != nullptr; |
|
96 } |
|
97 |
|
98 void CleanUpWidgetTracing() |
|
99 { |
|
100 CloseHandle(sEventHandle); |
|
101 sEventHandle = nullptr; |
|
102 } |
|
103 |
|
104 // This function is called from the main (UI) thread. |
|
105 void SignalTracerThread() |
|
106 { |
|
107 if (sEventHandle != nullptr) |
|
108 SetEvent(sEventHandle); |
|
109 } |
|
110 |
|
111 // This function is called from the background tracer thread. |
|
112 bool FireAndWaitForTracerEvent() |
|
113 { |
|
114 NS_ABORT_IF_FALSE(sEventHandle, "Tracing not initialized!"); |
|
115 |
|
116 // First, try to find the hidden window. |
|
117 static HWND hidden_window = nullptr; |
|
118 if (hidden_window == nullptr) { |
|
119 hidden_window = GetHiddenWindowHWND(); |
|
120 } |
|
121 |
|
122 if (hidden_window == nullptr) |
|
123 return false; |
|
124 |
|
125 // Post the tracer message into the hidden window's message queue, |
|
126 // and then block until it's processed. |
|
127 PostMessage(hidden_window, MOZ_WM_TRACE, 0, 0); |
|
128 WaitForSingleObject(sEventHandle, INFINITE); |
|
129 return true; |
|
130 } |
|
131 |
|
132 } // namespace mozilla |