1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/platform_thread.h"
8 #include "WinCompositorWindowThread.h"
9 #include "mozilla/gfx/Logging.h"
10 #include "mozilla/layers/SynchronousTask.h"
11 #include "mozilla/StaticPtr.h"
12 #include "transport/runnable_utils.h"
13 #include "mozilla/StaticPrefs_apz.h"
16 # define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
22 static StaticRefPtr
<WinCompositorWindowThread
> sWinCompositorWindowThread
;
24 WinCompositorWindowThread::WinCompositorWindowThread(base::Thread
* aThread
)
27 WinCompositorWindowThread::~WinCompositorWindowThread() { delete mThread
; }
30 WinCompositorWindowThread
* WinCompositorWindowThread::Get() {
31 return sWinCompositorWindowThread
;
35 void WinCompositorWindowThread::Start() {
36 MOZ_ASSERT(NS_IsMainThread());
37 MOZ_ASSERT(!sWinCompositorWindowThread
);
39 base::Thread
* thread
= new base::Thread("WinCompositor");
41 base::Thread::Options options
;
42 // HWND requests ui thread.
43 options
.message_loop_type
= MessageLoop::TYPE_UI
;
45 if (!thread
->StartWithOptions(options
)) {
50 sWinCompositorWindowThread
= new WinCompositorWindowThread(thread
);
54 void WinCompositorWindowThread::ShutDown() {
55 MOZ_ASSERT(NS_IsMainThread());
56 MOZ_ASSERT(sWinCompositorWindowThread
);
58 layers::SynchronousTask
task("WinCompositorWindowThread");
59 RefPtr
<Runnable
> runnable
= WrapRunnable(
60 RefPtr
<WinCompositorWindowThread
>(sWinCompositorWindowThread
.get()),
61 &WinCompositorWindowThread::ShutDownTask
, &task
);
62 sWinCompositorWindowThread
->Loop()->PostTask(runnable
.forget());
65 sWinCompositorWindowThread
= nullptr;
68 void WinCompositorWindowThread::ShutDownTask(layers::SynchronousTask
* aTask
) {
69 layers::AutoCompleteTask
complete(aTask
);
70 MOZ_ASSERT(IsInCompositorWindowThread());
74 MessageLoop
* WinCompositorWindowThread::Loop() {
75 return sWinCompositorWindowThread
76 ? sWinCompositorWindowThread
->mThread
->message_loop()
81 bool WinCompositorWindowThread::IsInCompositorWindowThread() {
82 return sWinCompositorWindowThread
&&
83 sWinCompositorWindowThread
->mThread
->thread_id() ==
84 PlatformThread::CurrentId();
87 const wchar_t kClassNameCompositorInitalParent
[] =
88 L
"MozillaCompositorInitialParentClass";
89 const wchar_t kClassNameCompositor
[] = L
"MozillaCompositorWindowClass";
91 ATOM g_compositor_inital_parent_window_class
;
92 ATOM g_compositor_window_class
;
94 // This runs on the window owner thread.
95 void InitializeInitialParentWindowClass() {
96 if (g_compositor_inital_parent_window_class
) {
102 wc
.lpfnWndProc
= ::DefWindowProcW
;
105 wc
.hInstance
= GetModuleHandle(nullptr);
107 wc
.hCursor
= nullptr;
108 wc
.hbrBackground
= nullptr;
109 wc
.lpszMenuName
= nullptr;
110 wc
.lpszClassName
= kClassNameCompositorInitalParent
;
111 g_compositor_inital_parent_window_class
= ::RegisterClassW(&wc
);
114 // This runs on the window owner thread.
115 void InitializeWindowClass() {
116 if (g_compositor_window_class
) {
122 wc
.lpfnWndProc
= ::DefWindowProcW
;
125 wc
.hInstance
= GetModuleHandle(nullptr);
127 wc
.hCursor
= nullptr;
128 wc
.hbrBackground
= nullptr;
129 wc
.lpszMenuName
= nullptr;
130 wc
.lpszClassName
= kClassNameCompositor
;
131 g_compositor_window_class
= ::RegisterClassW(&wc
);
135 WinCompositorWnds
WinCompositorWindowThread::CreateCompositorWindow() {
139 return WinCompositorWnds(nullptr, nullptr);
142 layers::SynchronousTask
task("Create compositor window");
144 HWND initialParentWnd
= nullptr;
145 HWND compositorWnd
= nullptr;
147 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
148 "WinCompositorWindowThread::CreateCompositorWindow::Runnable", [&]() {
149 layers::AutoCompleteTask
complete(&task
);
151 InitializeInitialParentWindowClass();
152 InitializeWindowClass();
154 // Create initial parent window.
155 // We could not directly create a compositor window with a main window
156 // as parent window, so instead create it with a temporary placeholder
157 // parent. Its parent is set as main window in UI process.
159 ::CreateWindowEx(WS_EX_TOOLWINDOW
, kClassNameCompositorInitalParent
,
160 nullptr, WS_POPUP
| WS_DISABLED
, 0, 0, 1, 1,
161 nullptr, 0, GetModuleHandle(nullptr), 0);
162 if (!initialParentWnd
) {
163 gfxCriticalNoteOnce
<< "Inital parent window failed "
168 DWORD extendedStyle
= WS_EX_NOPARENTNOTIFY
| WS_EX_NOREDIRECTIONBITMAP
;
170 if (!StaticPrefs::apz_windows_force_disable_direct_manipulation()) {
171 extendedStyle
|= WS_EX_LAYERED
| WS_EX_TRANSPARENT
;
174 compositorWnd
= ::CreateWindowEx(
175 extendedStyle
, kClassNameCompositor
, nullptr,
176 WS_CHILDWINDOW
| WS_DISABLED
| WS_VISIBLE
, 0, 0, 1, 1,
177 initialParentWnd
, 0, GetModuleHandle(nullptr), 0);
178 if (!compositorWnd
) {
179 gfxCriticalNoteOnce
<< "Compositor window failed "
184 Loop()->PostTask(runnable
.forget());
188 return WinCompositorWnds(compositorWnd
, initialParentWnd
);
192 void WinCompositorWindowThread::DestroyCompositorWindow(
193 WinCompositorWnds aWnds
) {
194 MOZ_ASSERT(aWnds
.mCompositorWnd
);
195 MOZ_ASSERT(aWnds
.mInitialParentWnd
);
202 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
203 "WinCompositorWidget::CreateNativeWindow::Runnable", [aWnds
]() {
204 ::DestroyWindow(aWnds
.mCompositorWnd
);
205 ::DestroyWindow(aWnds
.mInitialParentWnd
);
208 Loop()->PostTask(runnable
.forget());
211 } // namespace widget
212 } // namespace mozilla