/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Windows widget support for event loop instrumentation. * See toolkit/xre/EventTracer.cpp for more details. */ #include #include #include "mozilla/RefPtr.h" #include "mozilla/WidgetTraceEvent.h" #include "nsAppShellCID.h" #include "nsComponentManagerUtils.h" #include "nsCOMPtr.h" #include "nsIAppShellService.h" #include "nsIBaseWindow.h" #include "nsIDocShell.h" #include "nsISupportsImpl.h" #include "nsIWidget.h" #include "nsIAppWindow.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "nsWindowDefs.h" namespace { // Used for signaling the background thread from the main thread. HANDLE sEventHandle = nullptr; // We need a runnable in order to find the hidden window on the main // thread. class HWNDGetter : public mozilla::Runnable { public: HWNDGetter() : Runnable("HWNDGetter"), hidden_window_hwnd(nullptr) {} HWND hidden_window_hwnd; NS_IMETHOD Run() override { // Jump through some hoops to locate the hidden window. nsCOMPtr appShell( do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); nsCOMPtr hiddenWindow; nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr docShell; rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell)); if (NS_FAILED(rv) || !docShell) { return rv; } nsCOMPtr baseWindow(do_QueryInterface(docShell)); if (!baseWindow) return NS_ERROR_FAILURE; nsCOMPtr widget; baseWindow->GetMainWidget(getter_AddRefs(widget)); if (!widget) return NS_ERROR_FAILURE; hidden_window_hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW); return NS_OK; } }; HWND GetHiddenWindowHWND() { // Need to dispatch this to the main thread because plenty of // the things it wants to access are main-thread-only. RefPtr getter = new HWNDGetter(); NS_DispatchAndSpinEventLoopUntilComplete( "GetHiddenWindowHWND"_ns, mozilla::GetMainThreadSerialEventTarget(), do_AddRef(getter)); return getter->hidden_window_hwnd; } } // namespace namespace mozilla { bool InitWidgetTracing() { sEventHandle = CreateEventW(nullptr, FALSE, FALSE, nullptr); return sEventHandle != nullptr; } void CleanUpWidgetTracing() { CloseHandle(sEventHandle); sEventHandle = nullptr; } // This function is called from the main (UI) thread. void SignalTracerThread() { if (sEventHandle != nullptr) SetEvent(sEventHandle); } // This function is called from the background tracer thread. bool FireAndWaitForTracerEvent() { MOZ_ASSERT(sEventHandle, "Tracing not initialized!"); // First, try to find the hidden window. static HWND hidden_window = nullptr; if (hidden_window == nullptr) { hidden_window = GetHiddenWindowHWND(); } if (hidden_window == nullptr) return false; // Post the tracer message into the hidden window's message queue, // and then block until it's processed. PostMessage(hidden_window, MOZ_WM_TRACE, 0, 0); WaitForSingleObject(sEventHandle, INFINITE); return true; } } // namespace mozilla