child_window_win.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/child_window_win.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/compiler_specific.h"
  8. #include "base/debug/alias.h"
  9. #include "base/logging.h"
  10. #include "base/memory/weak_ptr.h"
  11. #include "base/message_loop/message_pump_type.h"
  12. #include "base/win/wrapped_window_proc.h"
  13. #include "ui/gfx/win/hwnd_util.h"
  14. #include "ui/gfx/win/window_impl.h"
  15. namespace gl {
  16. namespace {
  17. ATOM g_window_class;
  18. // This runs on the window owner thread.
  19. void InitializeWindowClass() {
  20. if (g_window_class)
  21. return;
  22. WNDCLASSEX intermediate_class;
  23. base::win::InitializeWindowClass(
  24. L"Intermediate D3D Window",
  25. &base::win::WrappedWindowProc<::DefWindowProc>, CS_OWNDC, 0, 0, nullptr,
  26. reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr, nullptr,
  27. nullptr, &intermediate_class);
  28. g_window_class = RegisterClassEx(&intermediate_class);
  29. if (!g_window_class) {
  30. LOG(ERROR) << "RegisterClass failed.";
  31. return;
  32. }
  33. }
  34. // Hidden popup window used as a parent for the child surface window.
  35. // Must be created and destroyed on the thread.
  36. class HiddenPopupWindow : public gfx::WindowImpl {
  37. public:
  38. static HWND Create() {
  39. gfx::WindowImpl* window = new HiddenPopupWindow;
  40. window->set_window_style(WS_POPUP);
  41. window->set_window_ex_style(WS_EX_TOOLWINDOW);
  42. window->Init(GetDesktopWindow(), gfx::Rect());
  43. EnableWindow(window->hwnd(), FALSE);
  44. // The |window| instance is now owned by the window user data.
  45. DCHECK_EQ(window, gfx::GetWindowUserData(window->hwnd()));
  46. return window->hwnd();
  47. }
  48. static void Destroy(HWND window) {
  49. // This uses the fact that the window user data contains a pointer
  50. // to gfx::WindowImpl instance.
  51. gfx::WindowImpl* window_data =
  52. reinterpret_cast<gfx::WindowImpl*>(gfx::GetWindowUserData(window));
  53. DCHECK_EQ(window, window_data->hwnd());
  54. DestroyWindow(window);
  55. delete window_data;
  56. }
  57. private:
  58. // Explicitly do nothing in Close. We do this as some external apps may get a
  59. // handle to this window and attempt to close it.
  60. void OnClose() {}
  61. CR_BEGIN_MSG_MAP_EX(HiddenPopupWindow)
  62. CR_MSG_WM_CLOSE(OnClose)
  63. CR_END_MSG_MAP()
  64. CR_MSG_MAP_CLASS_DECLARATIONS(HiddenPopupWindow)
  65. };
  66. // This runs on the window owner thread.
  67. void CreateWindowsOnThread(const gfx::Size& size,
  68. base::WaitableEvent* event,
  69. HWND* child_window,
  70. HWND* parent_window) {
  71. InitializeWindowClass();
  72. DCHECK(g_window_class);
  73. // Create hidden parent window on the current thread.
  74. *parent_window = HiddenPopupWindow::Create();
  75. // Create child window.
  76. // WS_EX_NOPARENTNOTIFY and WS_EX_LAYERED make the window transparent for
  77. // input. WS_EX_NOREDIRECTIONBITMAP avoids allocating a
  78. // bitmap that would otherwise be allocated with WS_EX_LAYERED, the bitmap is
  79. // only necessary if using Gdi objects with the window.
  80. HWND window = CreateWindowEx(
  81. WS_EX_NOPARENTNOTIFY | WS_EX_LAYERED | WS_EX_TRANSPARENT |
  82. WS_EX_NOREDIRECTIONBITMAP,
  83. reinterpret_cast<wchar_t*>(g_window_class), L"",
  84. WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, size.width(),
  85. size.height(), *parent_window, nullptr, nullptr, nullptr);
  86. if (!window) {
  87. logging::SystemErrorCode error = logging::GetLastSystemErrorCode();
  88. base::debug::Alias(&error);
  89. CHECK(false);
  90. }
  91. *child_window = window;
  92. event->Signal();
  93. }
  94. // This runs on the main thread after the window was destroyed on window owner
  95. // thread.
  96. void DestroyThread(std::unique_ptr<base::Thread> thread) {
  97. thread->Stop();
  98. }
  99. // This runs on the window owner thread.
  100. void DestroyWindowsOnThread(HWND child_window, HWND hidden_popup_window) {
  101. DestroyWindow(child_window);
  102. HiddenPopupWindow::Destroy(hidden_popup_window);
  103. }
  104. } // namespace
  105. ChildWindowWin::ChildWindowWin(HWND parent_window)
  106. : parent_window_(parent_window) {}
  107. void ChildWindowWin::Initialize() {
  108. if (window_)
  109. return;
  110. thread_ = std::make_unique<base::Thread>("Window owner thread");
  111. base::Thread::Options options(base::MessagePumpType::UI, 0);
  112. thread_->StartWithOptions(std::move(options));
  113. base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
  114. base::WaitableEvent::InitialState::NOT_SIGNALED);
  115. RECT window_rect;
  116. GetClientRect(parent_window_, &window_rect);
  117. thread_->task_runner()->PostTask(
  118. FROM_HERE,
  119. base::BindOnce(&CreateWindowsOnThread, gfx::Rect(window_rect).size(),
  120. &event, &window_, &initial_parent_window_));
  121. event.Wait();
  122. }
  123. ChildWindowWin::~ChildWindowWin() {
  124. if (thread_) {
  125. scoped_refptr<base::TaskRunner> task_runner = thread_->task_runner();
  126. task_runner->PostTaskAndReply(
  127. FROM_HERE,
  128. base::BindOnce(&DestroyWindowsOnThread, window_,
  129. initial_parent_window_),
  130. base::BindOnce(&DestroyThread, std::move(thread_)));
  131. }
  132. }
  133. scoped_refptr<base::TaskRunner> ChildWindowWin::GetTaskRunnerForTesting() {
  134. DCHECK(thread_);
  135. return thread_->task_runner();
  136. }
  137. } // namespace gl