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