summaryrefslogtreecommitdiffstats
path: root/widget/windows/WinCompositorWindowThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/windows/WinCompositorWindowThread.cpp212
1 files changed, 212 insertions, 0 deletions
diff --git a/widget/windows/WinCompositorWindowThread.cpp b/widget/windows/WinCompositorWindowThread.cpp
new file mode 100644
index 0000000000..f712522bc7
--- /dev/null
+++ b/widget/windows/WinCompositorWindowThread.cpp
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "base/platform_thread.h"
+#include "WinCompositorWindowThread.h"
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/SynchronousTask.h"
+#include "mozilla/StaticPtr.h"
+#include "transport/runnable_utils.h"
+#include "mozilla/StaticPrefs_apz.h"
+
+#if WINVER < 0x0602
+# define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
+#endif
+
+namespace mozilla {
+namespace widget {
+
+static StaticRefPtr<WinCompositorWindowThread> sWinCompositorWindowThread;
+
+WinCompositorWindowThread::WinCompositorWindowThread(base::Thread* aThread)
+ : mThread(aThread) {}
+
+WinCompositorWindowThread::~WinCompositorWindowThread() { delete mThread; }
+
+/* static */
+WinCompositorWindowThread* WinCompositorWindowThread::Get() {
+ return sWinCompositorWindowThread;
+}
+
+/* static */
+void WinCompositorWindowThread::Start() {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sWinCompositorWindowThread);
+
+ base::Thread* thread = new base::Thread("WinCompositor");
+
+ base::Thread::Options options;
+ // HWND requests ui thread.
+ options.message_loop_type = MessageLoop::TYPE_UI;
+
+ if (!thread->StartWithOptions(options)) {
+ delete thread;
+ return;
+ }
+
+ sWinCompositorWindowThread = new WinCompositorWindowThread(thread);
+}
+
+/* static */
+void WinCompositorWindowThread::ShutDown() {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(sWinCompositorWindowThread);
+
+ layers::SynchronousTask task("WinCompositorWindowThread");
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<WinCompositorWindowThread>(sWinCompositorWindowThread.get()),
+ &WinCompositorWindowThread::ShutDownTask, &task);
+ sWinCompositorWindowThread->Loop()->PostTask(runnable.forget());
+ task.Wait();
+
+ sWinCompositorWindowThread = nullptr;
+}
+
+void WinCompositorWindowThread::ShutDownTask(layers::SynchronousTask* aTask) {
+ layers::AutoCompleteTask complete(aTask);
+ MOZ_ASSERT(IsInCompositorWindowThread());
+}
+
+/* static */
+MessageLoop* WinCompositorWindowThread::Loop() {
+ return sWinCompositorWindowThread
+ ? sWinCompositorWindowThread->mThread->message_loop()
+ : nullptr;
+}
+
+/* static */
+bool WinCompositorWindowThread::IsInCompositorWindowThread() {
+ return sWinCompositorWindowThread &&
+ sWinCompositorWindowThread->mThread->thread_id() ==
+ PlatformThread::CurrentId();
+}
+
+const wchar_t kClassNameCompositorInitalParent[] =
+ L"MozillaCompositorInitialParentClass";
+const wchar_t kClassNameCompositor[] = L"MozillaCompositorWindowClass";
+
+ATOM g_compositor_inital_parent_window_class;
+ATOM g_compositor_window_class;
+
+// This runs on the window owner thread.
+void InitializeInitialParentWindowClass() {
+ if (g_compositor_inital_parent_window_class) {
+ return;
+ }
+
+ WNDCLASSW wc;
+ wc.style = 0;
+ wc.lpfnWndProc = ::DefWindowProcW;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(nullptr);
+ wc.hIcon = nullptr;
+ wc.hCursor = nullptr;
+ wc.hbrBackground = nullptr;
+ wc.lpszMenuName = nullptr;
+ wc.lpszClassName = kClassNameCompositorInitalParent;
+ g_compositor_inital_parent_window_class = ::RegisterClassW(&wc);
+}
+
+// This runs on the window owner thread.
+void InitializeWindowClass() {
+ if (g_compositor_window_class) {
+ return;
+ }
+
+ WNDCLASSW wc;
+ wc.style = CS_OWNDC;
+ wc.lpfnWndProc = ::DefWindowProcW;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(nullptr);
+ wc.hIcon = nullptr;
+ wc.hCursor = nullptr;
+ wc.hbrBackground = nullptr;
+ wc.lpszMenuName = nullptr;
+ wc.lpszClassName = kClassNameCompositor;
+ g_compositor_window_class = ::RegisterClassW(&wc);
+}
+
+/* static */
+WinCompositorWnds WinCompositorWindowThread::CreateCompositorWindow() {
+ MOZ_ASSERT(Loop());
+
+ if (!Loop()) {
+ return WinCompositorWnds(nullptr, nullptr);
+ }
+
+ layers::SynchronousTask task("Create compositor window");
+
+ HWND initialParentWnd = nullptr;
+ HWND compositorWnd = nullptr;
+
+ RefPtr<Runnable> runnable = NS_NewRunnableFunction(
+ "WinCompositorWindowThread::CreateCompositorWindow::Runnable", [&]() {
+ layers::AutoCompleteTask complete(&task);
+
+ InitializeInitialParentWindowClass();
+ InitializeWindowClass();
+
+ // Create initial parent window.
+ // We could not directly create a compositor window with a main window
+ // as parent window, so instead create it with a temporary placeholder
+ // parent. Its parent is set as main window in UI process.
+ initialParentWnd =
+ ::CreateWindowEx(WS_EX_TOOLWINDOW, kClassNameCompositorInitalParent,
+ nullptr, WS_POPUP | WS_DISABLED, 0, 0, 1, 1,
+ nullptr, 0, GetModuleHandle(nullptr), 0);
+ if (!initialParentWnd) {
+ gfxCriticalNoteOnce << "Inital parent window failed "
+ << ::GetLastError();
+ return;
+ }
+
+ DWORD extendedStyle = WS_EX_NOPARENTNOTIFY | WS_EX_NOREDIRECTIONBITMAP;
+
+ if (!StaticPrefs::apz_windows_force_disable_direct_manipulation()) {
+ extendedStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
+ }
+
+ compositorWnd = ::CreateWindowEx(
+ extendedStyle, kClassNameCompositor, nullptr,
+ WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, 1, 1,
+ initialParentWnd, 0, GetModuleHandle(nullptr), 0);
+ if (!compositorWnd) {
+ gfxCriticalNoteOnce << "Compositor window failed "
+ << ::GetLastError();
+ }
+ });
+
+ Loop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return WinCompositorWnds(compositorWnd, initialParentWnd);
+}
+
+/* static */
+void WinCompositorWindowThread::DestroyCompositorWindow(
+ WinCompositorWnds aWnds) {
+ MOZ_ASSERT(aWnds.mCompositorWnd);
+ MOZ_ASSERT(aWnds.mInitialParentWnd);
+ MOZ_ASSERT(Loop());
+
+ if (!Loop()) {
+ return;
+ }
+
+ RefPtr<Runnable> runnable = NS_NewRunnableFunction(
+ "WinCompositorWidget::CreateNativeWindow::Runnable", [aWnds]() {
+ ::DestroyWindow(aWnds.mCompositorWnd);
+ ::DestroyWindow(aWnds.mInitialParentWnd);
+ });
+
+ Loop()->PostTask(runnable.forget());
+}
+
+} // namespace widget
+} // namespace mozilla