| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * libjingle | |
| 3 * Copyright 2012 Google Inc. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions are met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright notice, | |
| 9 * this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| 11 * this list of conditions and the following disclaimer in the documentation | |
| 12 * and/or other materials provided with the distribution. | |
| 13 * 3. The name of the author may not be used to endorse or promote products | |
| 14 * derived from this software without specific prior written permission. | |
| 15 * | |
| 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
| 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
| 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
| 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
| 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
| 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
| 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 26 */ | |
| 27 | |
| 28 #include "talk/examples/peerconnection/client/main_wnd.h" | |
| 29 | |
| 30 #include <math.h> | |
| 31 | |
| 32 #include "talk/examples/peerconnection/client/defaults.h" | |
| 33 #include "webrtc/base/common.h" | |
| 34 #include "webrtc/base/logging.h" | |
| 35 | |
| 36 ATOM MainWnd::wnd_class_ = 0; | |
| 37 const wchar_t MainWnd::kClassName[] = L"WebRTC_MainWnd"; | |
| 38 | |
| 39 using rtc::sprintfn; | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 const char kConnecting[] = "Connecting... "; | |
| 44 const char kNoVideoStreams[] = "(no video streams either way)"; | |
| 45 const char kNoIncomingStream[] = "(no incoming video)"; | |
| 46 | |
| 47 void CalculateWindowSizeForText(HWND wnd, const wchar_t* text, | |
| 48 size_t* width, size_t* height) { | |
| 49 HDC dc = ::GetDC(wnd); | |
| 50 RECT text_rc = {0}; | |
| 51 ::DrawText(dc, text, -1, &text_rc, DT_CALCRECT | DT_SINGLELINE); | |
| 52 ::ReleaseDC(wnd, dc); | |
| 53 RECT client, window; | |
| 54 ::GetClientRect(wnd, &client); | |
| 55 ::GetWindowRect(wnd, &window); | |
| 56 | |
| 57 *width = text_rc.right - text_rc.left; | |
| 58 *width += (window.right - window.left) - | |
| 59 (client.right - client.left); | |
| 60 *height = text_rc.bottom - text_rc.top; | |
| 61 *height += (window.bottom - window.top) - | |
| 62 (client.bottom - client.top); | |
| 63 } | |
| 64 | |
| 65 HFONT GetDefaultFont() { | |
| 66 static HFONT font = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)); | |
| 67 return font; | |
| 68 } | |
| 69 | |
| 70 std::string GetWindowText(HWND wnd) { | |
| 71 char text[MAX_PATH] = {0}; | |
| 72 ::GetWindowTextA(wnd, &text[0], ARRAYSIZE(text)); | |
| 73 return text; | |
| 74 } | |
| 75 | |
| 76 void AddListBoxItem(HWND listbox, const std::string& str, LPARAM item_data) { | |
| 77 LRESULT index = ::SendMessageA(listbox, LB_ADDSTRING, 0, | |
| 78 reinterpret_cast<LPARAM>(str.c_str())); | |
| 79 ::SendMessageA(listbox, LB_SETITEMDATA, index, item_data); | |
| 80 } | |
| 81 | |
| 82 } // namespace | |
| 83 | |
| 84 MainWnd::MainWnd(const char* server, int port, bool auto_connect, | |
| 85 bool auto_call) | |
| 86 : ui_(CONNECT_TO_SERVER), wnd_(NULL), edit1_(NULL), edit2_(NULL), | |
| 87 label1_(NULL), label2_(NULL), button_(NULL), listbox_(NULL), | |
| 88 destroyed_(false), callback_(NULL), nested_msg_(NULL), | |
| 89 server_(server), auto_connect_(auto_connect), auto_call_(auto_call) { | |
| 90 char buffer[10] = {0}; | |
| 91 sprintfn(buffer, sizeof(buffer), "%i", port); | |
| 92 port_ = buffer; | |
| 93 } | |
| 94 | |
| 95 MainWnd::~MainWnd() { | |
| 96 ASSERT(!IsWindow()); | |
| 97 } | |
| 98 | |
| 99 bool MainWnd::Create() { | |
| 100 ASSERT(wnd_ == NULL); | |
| 101 if (!RegisterWindowClass()) | |
| 102 return false; | |
| 103 | |
| 104 ui_thread_id_ = ::GetCurrentThreadId(); | |
| 105 wnd_ = ::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC", | |
| 106 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, | |
| 107 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, | |
| 108 NULL, NULL, GetModuleHandle(NULL), this); | |
| 109 | |
| 110 ::SendMessage(wnd_, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()), | |
| 111 TRUE); | |
| 112 | |
| 113 CreateChildWindows(); | |
| 114 SwitchToConnectUI(); | |
| 115 | |
| 116 return wnd_ != NULL; | |
| 117 } | |
| 118 | |
| 119 bool MainWnd::Destroy() { | |
| 120 BOOL ret = FALSE; | |
| 121 if (IsWindow()) { | |
| 122 ret = ::DestroyWindow(wnd_); | |
| 123 } | |
| 124 | |
| 125 return ret != FALSE; | |
| 126 } | |
| 127 | |
| 128 void MainWnd::RegisterObserver(MainWndCallback* callback) { | |
| 129 callback_ = callback; | |
| 130 } | |
| 131 | |
| 132 bool MainWnd::IsWindow() { | |
| 133 return wnd_ && ::IsWindow(wnd_) != FALSE; | |
| 134 } | |
| 135 | |
| 136 bool MainWnd::PreTranslateMessage(MSG* msg) { | |
| 137 bool ret = false; | |
| 138 if (msg->message == WM_CHAR) { | |
| 139 if (msg->wParam == VK_TAB) { | |
| 140 HandleTabbing(); | |
| 141 ret = true; | |
| 142 } else if (msg->wParam == VK_RETURN) { | |
| 143 OnDefaultAction(); | |
| 144 ret = true; | |
| 145 } else if (msg->wParam == VK_ESCAPE) { | |
| 146 if (callback_) { | |
| 147 if (ui_ == STREAMING) { | |
| 148 callback_->DisconnectFromCurrentPeer(); | |
| 149 } else { | |
| 150 callback_->DisconnectFromServer(); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 } else if (msg->hwnd == NULL && msg->message == UI_THREAD_CALLBACK) { | |
| 155 callback_->UIThreadCallback(static_cast<int>(msg->wParam), | |
| 156 reinterpret_cast<void*>(msg->lParam)); | |
| 157 ret = true; | |
| 158 } | |
| 159 return ret; | |
| 160 } | |
| 161 | |
| 162 void MainWnd::SwitchToConnectUI() { | |
| 163 ASSERT(IsWindow()); | |
| 164 LayoutPeerListUI(false); | |
| 165 ui_ = CONNECT_TO_SERVER; | |
| 166 LayoutConnectUI(true); | |
| 167 ::SetFocus(edit1_); | |
| 168 | |
| 169 if (auto_connect_) | |
| 170 ::PostMessage(button_, BM_CLICK, 0, 0); | |
| 171 } | |
| 172 | |
| 173 void MainWnd::SwitchToPeerList(const Peers& peers) { | |
| 174 LayoutConnectUI(false); | |
| 175 | |
| 176 ::SendMessage(listbox_, LB_RESETCONTENT, 0, 0); | |
| 177 | |
| 178 AddListBoxItem(listbox_, "List of currently connected peers:", -1); | |
| 179 Peers::const_iterator i = peers.begin(); | |
| 180 for (; i != peers.end(); ++i) | |
| 181 AddListBoxItem(listbox_, i->second.c_str(), i->first); | |
| 182 | |
| 183 ui_ = LIST_PEERS; | |
| 184 LayoutPeerListUI(true); | |
| 185 ::SetFocus(listbox_); | |
| 186 | |
| 187 if (auto_call_ && peers.begin() != peers.end()) { | |
| 188 // Get the number of items in the list | |
| 189 LRESULT count = ::SendMessage(listbox_, LB_GETCOUNT, 0, 0); | |
| 190 if (count != LB_ERR) { | |
| 191 // Select the last item in the list | |
| 192 LRESULT selection = ::SendMessage(listbox_, LB_SETCURSEL , count - 1, 0); | |
| 193 if (selection != LB_ERR) | |
| 194 ::PostMessage(wnd_, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(listbox_), | |
| 195 LBN_DBLCLK), | |
| 196 reinterpret_cast<LPARAM>(listbox_)); | |
| 197 } | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 void MainWnd::SwitchToStreamingUI() { | |
| 202 LayoutConnectUI(false); | |
| 203 LayoutPeerListUI(false); | |
| 204 ui_ = STREAMING; | |
| 205 } | |
| 206 | |
| 207 void MainWnd::MessageBox(const char* caption, const char* text, bool is_error) { | |
| 208 DWORD flags = MB_OK; | |
| 209 if (is_error) | |
| 210 flags |= MB_ICONERROR; | |
| 211 | |
| 212 ::MessageBoxA(handle(), text, caption, flags); | |
| 213 } | |
| 214 | |
| 215 | |
| 216 void MainWnd::StartLocalRenderer(webrtc::VideoTrackInterface* local_video) { | |
| 217 local_renderer_.reset(new VideoRenderer(handle(), 1, 1, local_video)); | |
| 218 } | |
| 219 | |
| 220 void MainWnd::StopLocalRenderer() { | |
| 221 local_renderer_.reset(); | |
| 222 } | |
| 223 | |
| 224 void MainWnd::StartRemoteRenderer(webrtc::VideoTrackInterface* remote_video) { | |
| 225 remote_renderer_.reset(new VideoRenderer(handle(), 1, 1, remote_video)); | |
| 226 } | |
| 227 | |
| 228 void MainWnd::StopRemoteRenderer() { | |
| 229 remote_renderer_.reset(); | |
| 230 } | |
| 231 | |
| 232 void MainWnd::QueueUIThreadCallback(int msg_id, void* data) { | |
| 233 ::PostThreadMessage(ui_thread_id_, UI_THREAD_CALLBACK, | |
| 234 static_cast<WPARAM>(msg_id), reinterpret_cast<LPARAM>(data)); | |
| 235 } | |
| 236 | |
| 237 void MainWnd::OnPaint() { | |
| 238 PAINTSTRUCT ps; | |
| 239 ::BeginPaint(handle(), &ps); | |
| 240 | |
| 241 RECT rc; | |
| 242 ::GetClientRect(handle(), &rc); | |
| 243 | |
| 244 VideoRenderer* local_renderer = local_renderer_.get(); | |
| 245 VideoRenderer* remote_renderer = remote_renderer_.get(); | |
| 246 if (ui_ == STREAMING && remote_renderer && local_renderer) { | |
| 247 AutoLock<VideoRenderer> local_lock(local_renderer); | |
| 248 AutoLock<VideoRenderer> remote_lock(remote_renderer); | |
| 249 | |
| 250 const BITMAPINFO& bmi = remote_renderer->bmi(); | |
| 251 int height = abs(bmi.bmiHeader.biHeight); | |
| 252 int width = bmi.bmiHeader.biWidth; | |
| 253 | |
| 254 const uint8* image = remote_renderer->image(); | |
| 255 if (image != NULL) { | |
| 256 HDC dc_mem = ::CreateCompatibleDC(ps.hdc); | |
| 257 ::SetStretchBltMode(dc_mem, HALFTONE); | |
| 258 | |
| 259 // Set the map mode so that the ratio will be maintained for us. | |
| 260 HDC all_dc[] = { ps.hdc, dc_mem }; | |
| 261 for (int i = 0; i < ARRAY_SIZE(all_dc); ++i) { | |
| 262 SetMapMode(all_dc[i], MM_ISOTROPIC); | |
| 263 SetWindowExtEx(all_dc[i], width, height, NULL); | |
| 264 SetViewportExtEx(all_dc[i], rc.right, rc.bottom, NULL); | |
| 265 } | |
| 266 | |
| 267 HBITMAP bmp_mem = ::CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom); | |
| 268 HGDIOBJ bmp_old = ::SelectObject(dc_mem, bmp_mem); | |
| 269 | |
| 270 POINT logical_area = { rc.right, rc.bottom }; | |
| 271 DPtoLP(ps.hdc, &logical_area, 1); | |
| 272 | |
| 273 HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); | |
| 274 RECT logical_rect = {0, 0, logical_area.x, logical_area.y }; | |
| 275 ::FillRect(dc_mem, &logical_rect, brush); | |
| 276 ::DeleteObject(brush); | |
| 277 | |
| 278 int x = (logical_area.x / 2) - (width / 2); | |
| 279 int y = (logical_area.y / 2) - (height / 2); | |
| 280 | |
| 281 StretchDIBits(dc_mem, x, y, width, height, | |
| 282 0, 0, width, height, image, &bmi, DIB_RGB_COLORS, SRCCOPY); | |
| 283 | |
| 284 if ((rc.right - rc.left) > 200 && (rc.bottom - rc.top) > 200) { | |
| 285 const BITMAPINFO& bmi = local_renderer->bmi(); | |
| 286 image = local_renderer->image(); | |
| 287 int thumb_width = bmi.bmiHeader.biWidth / 4; | |
| 288 int thumb_height = abs(bmi.bmiHeader.biHeight) / 4; | |
| 289 StretchDIBits(dc_mem, | |
| 290 logical_area.x - thumb_width - 10, | |
| 291 logical_area.y - thumb_height - 10, | |
| 292 thumb_width, thumb_height, | |
| 293 0, 0, bmi.bmiHeader.biWidth, -bmi.bmiHeader.biHeight, | |
| 294 image, &bmi, DIB_RGB_COLORS, SRCCOPY); | |
| 295 } | |
| 296 | |
| 297 BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y, | |
| 298 dc_mem, 0, 0, SRCCOPY); | |
| 299 | |
| 300 // Cleanup. | |
| 301 ::SelectObject(dc_mem, bmp_old); | |
| 302 ::DeleteObject(bmp_mem); | |
| 303 ::DeleteDC(dc_mem); | |
| 304 } else { | |
| 305 // We're still waiting for the video stream to be initialized. | |
| 306 HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); | |
| 307 ::FillRect(ps.hdc, &rc, brush); | |
| 308 ::DeleteObject(brush); | |
| 309 | |
| 310 HGDIOBJ old_font = ::SelectObject(ps.hdc, GetDefaultFont()); | |
| 311 ::SetTextColor(ps.hdc, RGB(0xff, 0xff, 0xff)); | |
| 312 ::SetBkMode(ps.hdc, TRANSPARENT); | |
| 313 | |
| 314 std::string text(kConnecting); | |
| 315 if (!local_renderer->image()) { | |
| 316 text += kNoVideoStreams; | |
| 317 } else { | |
| 318 text += kNoIncomingStream; | |
| 319 } | |
| 320 ::DrawTextA(ps.hdc, text.c_str(), -1, &rc, | |
| 321 DT_SINGLELINE | DT_CENTER | DT_VCENTER); | |
| 322 ::SelectObject(ps.hdc, old_font); | |
| 323 } | |
| 324 } else { | |
| 325 HBRUSH brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW)); | |
| 326 ::FillRect(ps.hdc, &rc, brush); | |
| 327 ::DeleteObject(brush); | |
| 328 } | |
| 329 | |
| 330 ::EndPaint(handle(), &ps); | |
| 331 } | |
| 332 | |
| 333 void MainWnd::OnDestroyed() { | |
| 334 PostQuitMessage(0); | |
| 335 } | |
| 336 | |
| 337 void MainWnd::OnDefaultAction() { | |
| 338 if (!callback_) | |
| 339 return; | |
| 340 if (ui_ == CONNECT_TO_SERVER) { | |
| 341 std::string server(GetWindowText(edit1_)); | |
| 342 std::string port_str(GetWindowText(edit2_)); | |
| 343 int port = port_str.length() ? atoi(port_str.c_str()) : 0; | |
| 344 callback_->StartLogin(server, port); | |
| 345 } else if (ui_ == LIST_PEERS) { | |
| 346 LRESULT sel = ::SendMessage(listbox_, LB_GETCURSEL, 0, 0); | |
| 347 if (sel != LB_ERR) { | |
| 348 LRESULT peer_id = ::SendMessage(listbox_, LB_GETITEMDATA, sel, 0); | |
| 349 if (peer_id != -1 && callback_) { | |
| 350 callback_->ConnectToPeer(peer_id); | |
| 351 } | |
| 352 } | |
| 353 } else { | |
| 354 MessageBoxA(wnd_, "OK!", "Yeah", MB_OK); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) { | |
| 359 switch (msg) { | |
| 360 case WM_ERASEBKGND: | |
| 361 *result = TRUE; | |
| 362 return true; | |
| 363 | |
| 364 case WM_PAINT: | |
| 365 OnPaint(); | |
| 366 return true; | |
| 367 | |
| 368 case WM_SETFOCUS: | |
| 369 if (ui_ == CONNECT_TO_SERVER) { | |
| 370 SetFocus(edit1_); | |
| 371 } else if (ui_ == LIST_PEERS) { | |
| 372 SetFocus(listbox_); | |
| 373 } | |
| 374 return true; | |
| 375 | |
| 376 case WM_SIZE: | |
| 377 if (ui_ == CONNECT_TO_SERVER) { | |
| 378 LayoutConnectUI(true); | |
| 379 } else if (ui_ == LIST_PEERS) { | |
| 380 LayoutPeerListUI(true); | |
| 381 } | |
| 382 break; | |
| 383 | |
| 384 case WM_CTLCOLORSTATIC: | |
| 385 *result = reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_WINDOW)); | |
| 386 return true; | |
| 387 | |
| 388 case WM_COMMAND: | |
| 389 if (button_ == reinterpret_cast<HWND>(lp)) { | |
| 390 if (BN_CLICKED == HIWORD(wp)) | |
| 391 OnDefaultAction(); | |
| 392 } else if (listbox_ == reinterpret_cast<HWND>(lp)) { | |
| 393 if (LBN_DBLCLK == HIWORD(wp)) { | |
| 394 OnDefaultAction(); | |
| 395 } | |
| 396 } | |
| 397 return true; | |
| 398 | |
| 399 case WM_CLOSE: | |
| 400 if (callback_) | |
| 401 callback_->Close(); | |
| 402 break; | |
| 403 } | |
| 404 return false; | |
| 405 } | |
| 406 | |
| 407 // static | |
| 408 LRESULT CALLBACK MainWnd::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { | |
| 409 MainWnd* me = reinterpret_cast<MainWnd*>( | |
| 410 ::GetWindowLongPtr(hwnd, GWLP_USERDATA)); | |
| 411 if (!me && WM_CREATE == msg) { | |
| 412 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lp); | |
| 413 me = reinterpret_cast<MainWnd*>(cs->lpCreateParams); | |
| 414 me->wnd_ = hwnd; | |
| 415 ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(me)); | |
| 416 } | |
| 417 | |
| 418 LRESULT result = 0; | |
| 419 if (me) { | |
| 420 void* prev_nested_msg = me->nested_msg_; | |
| 421 me->nested_msg_ = &msg; | |
| 422 | |
| 423 bool handled = me->OnMessage(msg, wp, lp, &result); | |
| 424 if (WM_NCDESTROY == msg) { | |
| 425 me->destroyed_ = true; | |
| 426 } else if (!handled) { | |
| 427 result = ::DefWindowProc(hwnd, msg, wp, lp); | |
| 428 } | |
| 429 | |
| 430 if (me->destroyed_ && prev_nested_msg == NULL) { | |
| 431 me->OnDestroyed(); | |
| 432 me->wnd_ = NULL; | |
| 433 me->destroyed_ = false; | |
| 434 } | |
| 435 | |
| 436 me->nested_msg_ = prev_nested_msg; | |
| 437 } else { | |
| 438 result = ::DefWindowProc(hwnd, msg, wp, lp); | |
| 439 } | |
| 440 | |
| 441 return result; | |
| 442 } | |
| 443 | |
| 444 // static | |
| 445 bool MainWnd::RegisterWindowClass() { | |
| 446 if (wnd_class_) | |
| 447 return true; | |
| 448 | |
| 449 WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; | |
| 450 wcex.style = CS_DBLCLKS; | |
| 451 wcex.hInstance = GetModuleHandle(NULL); | |
| 452 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1); | |
| 453 wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW); | |
| 454 wcex.lpfnWndProc = &WndProc; | |
| 455 wcex.lpszClassName = kClassName; | |
| 456 wnd_class_ = ::RegisterClassEx(&wcex); | |
| 457 ASSERT(wnd_class_ != 0); | |
| 458 return wnd_class_ != 0; | |
| 459 } | |
| 460 | |
| 461 void MainWnd::CreateChildWindow(HWND* wnd, MainWnd::ChildWindowID id, | |
| 462 const wchar_t* class_name, DWORD control_style, | |
| 463 DWORD ex_style) { | |
| 464 if (::IsWindow(*wnd)) | |
| 465 return; | |
| 466 | |
| 467 // Child windows are invisible at first, and shown after being resized. | |
| 468 DWORD style = WS_CHILD | control_style; | |
| 469 *wnd = ::CreateWindowEx(ex_style, class_name, L"", style, | |
| 470 100, 100, 100, 100, wnd_, | |
| 471 reinterpret_cast<HMENU>(id), | |
| 472 GetModuleHandle(NULL), NULL); | |
| 473 ASSERT(::IsWindow(*wnd) != FALSE); | |
| 474 ::SendMessage(*wnd, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()), | |
| 475 TRUE); | |
| 476 } | |
| 477 | |
| 478 void MainWnd::CreateChildWindows() { | |
| 479 // Create the child windows in tab order. | |
| 480 CreateChildWindow(&label1_, LABEL1_ID, L"Static", ES_CENTER | ES_READONLY, 0); | |
| 481 CreateChildWindow(&edit1_, EDIT_ID, L"Edit", | |
| 482 ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, WS_EX_CLIENTEDGE); | |
| 483 CreateChildWindow(&label2_, LABEL2_ID, L"Static", ES_CENTER | ES_READONLY, 0); | |
| 484 CreateChildWindow(&edit2_, EDIT_ID, L"Edit", | |
| 485 ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, WS_EX_CLIENTEDGE); | |
| 486 CreateChildWindow(&button_, BUTTON_ID, L"Button", BS_CENTER | WS_TABSTOP, 0); | |
| 487 | |
| 488 CreateChildWindow(&listbox_, LISTBOX_ID, L"ListBox", | |
| 489 LBS_HASSTRINGS | LBS_NOTIFY, WS_EX_CLIENTEDGE); | |
| 490 | |
| 491 ::SetWindowTextA(edit1_, server_.c_str()); | |
| 492 ::SetWindowTextA(edit2_, port_.c_str()); | |
| 493 } | |
| 494 | |
| 495 void MainWnd::LayoutConnectUI(bool show) { | |
| 496 struct Windows { | |
| 497 HWND wnd; | |
| 498 const wchar_t* text; | |
| 499 size_t width; | |
| 500 size_t height; | |
| 501 } windows[] = { | |
| 502 { label1_, L"Server" }, | |
| 503 { edit1_, L"XXXyyyYYYgggXXXyyyYYYggg" }, | |
| 504 { label2_, L":" }, | |
| 505 { edit2_, L"XyXyX" }, | |
| 506 { button_, L"Connect" }, | |
| 507 }; | |
| 508 | |
| 509 if (show) { | |
| 510 const size_t kSeparator = 5; | |
| 511 size_t total_width = (ARRAYSIZE(windows) - 1) * kSeparator; | |
| 512 | |
| 513 for (size_t i = 0; i < ARRAYSIZE(windows); ++i) { | |
| 514 CalculateWindowSizeForText(windows[i].wnd, windows[i].text, | |
| 515 &windows[i].width, &windows[i].height); | |
| 516 total_width += windows[i].width; | |
| 517 } | |
| 518 | |
| 519 RECT rc; | |
| 520 ::GetClientRect(wnd_, &rc); | |
| 521 size_t x = (rc.right / 2) - (total_width / 2); | |
| 522 size_t y = rc.bottom / 2; | |
| 523 for (size_t i = 0; i < ARRAYSIZE(windows); ++i) { | |
| 524 size_t top = y - (windows[i].height / 2); | |
| 525 ::MoveWindow(windows[i].wnd, static_cast<int>(x), static_cast<int>(top), | |
| 526 static_cast<int>(windows[i].width), | |
| 527 static_cast<int>(windows[i].height), | |
| 528 TRUE); | |
| 529 x += kSeparator + windows[i].width; | |
| 530 if (windows[i].text[0] != 'X') | |
| 531 ::SetWindowText(windows[i].wnd, windows[i].text); | |
| 532 ::ShowWindow(windows[i].wnd, SW_SHOWNA); | |
| 533 } | |
| 534 } else { | |
| 535 for (size_t i = 0; i < ARRAYSIZE(windows); ++i) { | |
| 536 ::ShowWindow(windows[i].wnd, SW_HIDE); | |
| 537 } | |
| 538 } | |
| 539 } | |
| 540 | |
| 541 void MainWnd::LayoutPeerListUI(bool show) { | |
| 542 if (show) { | |
| 543 RECT rc; | |
| 544 ::GetClientRect(wnd_, &rc); | |
| 545 ::MoveWindow(listbox_, 0, 0, rc.right, rc.bottom, TRUE); | |
| 546 ::ShowWindow(listbox_, SW_SHOWNA); | |
| 547 } else { | |
| 548 ::ShowWindow(listbox_, SW_HIDE); | |
| 549 InvalidateRect(wnd_, NULL, TRUE); | |
| 550 } | |
| 551 } | |
| 552 | |
| 553 void MainWnd::HandleTabbing() { | |
| 554 bool shift = ((::GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0); | |
| 555 UINT next_cmd = shift ? GW_HWNDPREV : GW_HWNDNEXT; | |
| 556 UINT loop_around_cmd = shift ? GW_HWNDLAST : GW_HWNDFIRST; | |
| 557 HWND focus = GetFocus(), next; | |
| 558 do { | |
| 559 next = ::GetWindow(focus, next_cmd); | |
| 560 if (IsWindowVisible(next) && | |
| 561 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP)) { | |
| 562 break; | |
| 563 } | |
| 564 | |
| 565 if (!next) { | |
| 566 next = ::GetWindow(focus, loop_around_cmd); | |
| 567 if (IsWindowVisible(next) && | |
| 568 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP)) { | |
| 569 break; | |
| 570 } | |
| 571 } | |
| 572 focus = next; | |
| 573 } while (true); | |
| 574 ::SetFocus(next); | |
| 575 } | |
| 576 | |
| 577 // | |
| 578 // MainWnd::VideoRenderer | |
| 579 // | |
| 580 | |
| 581 MainWnd::VideoRenderer::VideoRenderer( | |
| 582 HWND wnd, int width, int height, | |
| 583 webrtc::VideoTrackInterface* track_to_render) | |
| 584 : wnd_(wnd), rendered_track_(track_to_render) { | |
| 585 ::InitializeCriticalSection(&buffer_lock_); | |
| 586 ZeroMemory(&bmi_, sizeof(bmi_)); | |
| 587 bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
| 588 bmi_.bmiHeader.biPlanes = 1; | |
| 589 bmi_.bmiHeader.biBitCount = 32; | |
| 590 bmi_.bmiHeader.biCompression = BI_RGB; | |
| 591 bmi_.bmiHeader.biWidth = width; | |
| 592 bmi_.bmiHeader.biHeight = -height; | |
| 593 bmi_.bmiHeader.biSizeImage = width * height * | |
| 594 (bmi_.bmiHeader.biBitCount >> 3); | |
| 595 rendered_track_->AddRenderer(this); | |
| 596 } | |
| 597 | |
| 598 MainWnd::VideoRenderer::~VideoRenderer() { | |
| 599 rendered_track_->RemoveRenderer(this); | |
| 600 ::DeleteCriticalSection(&buffer_lock_); | |
| 601 } | |
| 602 | |
| 603 void MainWnd::VideoRenderer::SetSize(int width, int height) { | |
| 604 AutoLock<VideoRenderer> lock(this); | |
| 605 | |
| 606 if (width == bmi_.bmiHeader.biWidth && height == bmi_.bmiHeader.biHeight) { | |
| 607 return; | |
| 608 } | |
| 609 | |
| 610 bmi_.bmiHeader.biWidth = width; | |
| 611 bmi_.bmiHeader.biHeight = -height; | |
| 612 bmi_.bmiHeader.biSizeImage = width * height * | |
| 613 (bmi_.bmiHeader.biBitCount >> 3); | |
| 614 image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]); | |
| 615 } | |
| 616 | |
| 617 void MainWnd::VideoRenderer::RenderFrame( | |
| 618 const cricket::VideoFrame* video_frame) { | |
| 619 if (!video_frame) | |
| 620 return; | |
| 621 | |
| 622 { | |
| 623 AutoLock<VideoRenderer> lock(this); | |
| 624 | |
| 625 const cricket::VideoFrame* frame = | |
| 626 video_frame->GetCopyWithRotationApplied(); | |
| 627 | |
| 628 SetSize(static_cast<int>(frame->GetWidth()), | |
| 629 static_cast<int>(frame->GetHeight())); | |
| 630 | |
| 631 ASSERT(image_.get() != NULL); | |
| 632 frame->ConvertToRgbBuffer(cricket::FOURCC_ARGB, | |
| 633 image_.get(), | |
| 634 bmi_.bmiHeader.biSizeImage, | |
| 635 bmi_.bmiHeader.biWidth * | |
| 636 bmi_.bmiHeader.biBitCount / 8); | |
| 637 } | |
| 638 InvalidateRect(wnd_, NULL, TRUE); | |
| 639 } | |
| OLD | NEW |