1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "platform_uithread.h"
12
13 namespace rtc {
14
15 #if defined(WEBRTC_WIN)
16
17 // timer id used in delayed callbacks
18 static const UINT_PTR kTimerId = 1;
19 static const wchar_t kThisProperty[] = L"ThreadWindowsUIPtr";
20 static const wchar_t kThreadWindow[] = L"WebrtcWindowsUIThread";
21
InternalInit()22 bool PlatformUIThread::InternalInit() {
23 // Create an event window for use in generating callbacks to capture
24 // objects.
25 CritScope scoped_lock(&cs_);
26 if (hwnd_ == NULL) {
27 WNDCLASSW wc;
28 HMODULE hModule = GetModuleHandle(NULL);
29 if (!GetClassInfoW(hModule, kThreadWindow, &wc)) {
30 ZeroMemory(&wc, sizeof(WNDCLASSW));
31 wc.hInstance = hModule;
32 wc.lpfnWndProc = EventWindowProc;
33 wc.lpszClassName = kThreadWindow;
34 RegisterClassW(&wc);
35 }
36 hwnd_ = CreateWindowW(kThreadWindow, L"", 0, 0, 0, 0, 0, NULL, NULL,
37 hModule, NULL);
38 RTC_DCHECK(hwnd_);
39 SetPropW(hwnd_, kThisProperty, this);
40
41 if (timeout_) {
42 // if someone set the timer before we started
43 RequestCallbackTimer(timeout_);
44 }
45 }
46 return !!hwnd_;
47 }
48
RequestCallbackTimer(unsigned int milliseconds)49 bool PlatformUIThread::RequestCallbackTimer(unsigned int milliseconds) {
50 CritScope scoped_lock(&cs_);
51 if (!hwnd_) {
52 // There is a condition that thread_ (PlatformUIThread) has been
53 // created but PlatformUIThread::Run() hasn't been run yet (hwnd_ is
54 // null while thread_ is not). If we do RTC_DCHECK(!thread_) here,
55 // it would lead to crash in this condition.
56
57 // set timer once thread starts
58 } else {
59 if (timerid_) {
60 KillTimer(hwnd_, timerid_);
61 }
62 timerid_ = SetTimer(hwnd_, kTimerId, milliseconds, NULL);
63 }
64 timeout_ = milliseconds;
65 return !!timerid_;
66 }
67
Stop()68 void PlatformUIThread::Stop() {
69 RTC_DCHECK(thread_checker_.CalledOnValidThread());
70 // Shut down the dispatch loop and let the background thread exit.
71 if (timerid_) {
72 KillTimer(hwnd_, timerid_);
73 timerid_ = 0;
74 }
75
76 PostMessage(hwnd_, WM_CLOSE, 0, 0);
77
78 hwnd_ = NULL;
79
80 PlatformThread::Stop();
81 }
82
Run()83 void PlatformUIThread::Run() {
84 RTC_CHECK(InternalInit()); // always evaluates
85 // The interface contract of Start/Stop is that for a successful call to
86 // Start, there should be at least one call to the run function. So we
87 // call the function before checking |stop_|.
88 run_function_deprecated_(obj_);
89
90 do {
91 // Alertable sleep to permit RaiseFlag to run and update |stop_|.
92 if (MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLINPUT,
93 MWMO_ALERTABLE | MWMO_INPUTAVAILABLE) ==
94 WAIT_OBJECT_0) {
95 MSG msg;
96 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
97 if (msg.message == WM_QUIT) {
98 stop_ = true;
99 break;
100 }
101 TranslateMessage(&msg);
102 DispatchMessage(&msg);
103 }
104 }
105
106 } while (!stop_);
107 }
108
NativeEventCallback()109 void PlatformUIThread::NativeEventCallback() {
110 if (!run_function_deprecated_) {
111 stop_ = true;
112 return;
113 }
114 run_function_deprecated_(obj_);
115 }
116
117 /* static */
EventWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)118 LRESULT CALLBACK PlatformUIThread::EventWindowProc(HWND hwnd, UINT uMsg,
119 WPARAM wParam,
120 LPARAM lParam) {
121 if (uMsg == WM_DESTROY) {
122 RemovePropW(hwnd, kThisProperty);
123 PostQuitMessage(0);
124 return 0;
125 }
126
127 PlatformUIThread* twui =
128 static_cast<PlatformUIThread*>(GetPropW(hwnd, kThisProperty));
129 if (!twui) {
130 return DefWindowProc(hwnd, uMsg, wParam, lParam);
131 }
132
133 if (uMsg == WM_TIMER && wParam == kTimerId) {
134 twui->NativeEventCallback();
135 return 0;
136 }
137
138 return DefWindowProc(hwnd, uMsg, wParam, lParam);
139 }
140 #endif
141
142 } // namespace rtc
143