diff options
Diffstat (limited to 'widget/windows/WidgetTraceEvent.cpp')
-rw-r--r-- | widget/windows/WidgetTraceEvent.cpp | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/widget/windows/WidgetTraceEvent.cpp b/widget/windows/WidgetTraceEvent.cpp new file mode 100644 index 0000000000..15bb4d720c --- /dev/null +++ b/widget/windows/WidgetTraceEvent.cpp @@ -0,0 +1,121 @@ +/* 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 <stdio.h> +#include <windows.h> + +#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<nsIAppShellService> appShell( + do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); + nsCOMPtr<nsIAppWindow> hiddenWindow; + + nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); + if (NS_FAILED(rv)) { + return rv; + } + + nsCOMPtr<nsIDocShell> docShell; + rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell)); + if (NS_FAILED(rv) || !docShell) { + return rv; + } + + nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell)); + + if (!baseWindow) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIWidget> 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<HWNDGetter> 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 |