summaryrefslogtreecommitdiffstats
path: root/widget/windows/WidgetTraceEvent.cpp
blob: 15bb4d720c76bb2ea659cbf9a346d4ef43085bd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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