This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
Use hidden window to process flutter messages #24232
Merged
cbracken
merged 1 commit into
flutter:master
from
knopp:windows_hidden_window_for_messages
Mar 4, 2021
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "flutter/shell/platform/windows/task_runner_win32_window.h" | ||
|
||
#include <algorithm> | ||
#include <iostream> | ||
|
||
namespace flutter { | ||
|
||
TaskRunnerWin32Window::TaskRunnerWin32Window() { | ||
WNDCLASS window_class = RegisterWindowClass(); | ||
window_handle_ = | ||
CreateWindowEx(0, window_class.lpszClassName, L"", 0, 0, 0, 0, 0, | ||
HWND_MESSAGE, nullptr, window_class.hInstance, nullptr); | ||
|
||
if (window_handle_) { | ||
SetWindowLongPtr(window_handle_, GWLP_USERDATA, | ||
reinterpret_cast<LONG_PTR>(this)); | ||
} else { | ||
auto error = GetLastError(); | ||
LPWSTR message = nullptr; | ||
size_t size = FormatMessageW( | ||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | | ||
FORMAT_MESSAGE_IGNORE_INSERTS, | ||
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||
reinterpret_cast<LPWSTR>(&message), 0, NULL); | ||
OutputDebugString(message); | ||
LocalFree(message); | ||
} | ||
} | ||
|
||
TaskRunnerWin32Window::~TaskRunnerWin32Window() { | ||
if (window_handle_) { | ||
DestroyWindow(window_handle_); | ||
window_handle_ = nullptr; | ||
} | ||
UnregisterClass(window_class_name_.c_str(), nullptr); | ||
} | ||
|
||
std::shared_ptr<TaskRunnerWin32Window> | ||
TaskRunnerWin32Window::GetSharedInstance() { | ||
static std::weak_ptr<TaskRunnerWin32Window> instance; | ||
auto res = instance.lock(); | ||
if (!res) { | ||
// can't use make_shared with private contructor | ||
res.reset(new TaskRunnerWin32Window()); | ||
instance = res; | ||
} | ||
return res; | ||
} | ||
|
||
void TaskRunnerWin32Window::WakeUp() { | ||
if (!PostMessage(window_handle_, WM_NULL, 0, 0)) { | ||
std::cerr << "Failed to post message to main thread." << std::endl; | ||
} | ||
} | ||
|
||
void TaskRunnerWin32Window::AddDelegate(Delegate* delegate) { | ||
delegates_.push_back(delegate); | ||
SetTimer(std::chrono::nanoseconds::zero()); | ||
} | ||
|
||
void TaskRunnerWin32Window::RemoveDelegate(Delegate* delegate) { | ||
auto i = std::find(delegates_.begin(), delegates_.end(), delegate); | ||
if (i != delegates_.end()) { | ||
delegates_.erase(i); | ||
} | ||
} | ||
|
||
void TaskRunnerWin32Window::ProcessTasks() { | ||
auto next = std::chrono::nanoseconds::max(); | ||
auto delegates_copy(delegates_); | ||
for (auto delegate : delegates_copy) { | ||
// if not removed in the meanwhile | ||
if (std::find(delegates_.begin(), delegates_.end(), delegate) != | ||
delegates_.end()) { | ||
next = std::min(next, delegate->ProcessTasks()); | ||
} | ||
} | ||
SetTimer(next); | ||
} | ||
|
||
void TaskRunnerWin32Window::SetTimer(std::chrono::nanoseconds when) { | ||
if (when == std::chrono::nanoseconds::max()) { | ||
KillTimer(window_handle_, 0); | ||
} else { | ||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(when); | ||
::SetTimer(window_handle_, 0, millis.count() + 1, nullptr); | ||
} | ||
} | ||
|
||
WNDCLASS TaskRunnerWin32Window::RegisterWindowClass() { | ||
window_class_name_ = L"FlutterTaskRunnerWindow"; | ||
|
||
WNDCLASS window_class{}; | ||
window_class.hCursor = nullptr; | ||
window_class.lpszClassName = window_class_name_.c_str(); | ||
window_class.style = 0; | ||
window_class.cbClsExtra = 0; | ||
window_class.cbWndExtra = 0; | ||
window_class.hInstance = GetModuleHandle(nullptr); | ||
window_class.hIcon = nullptr; | ||
window_class.hbrBackground = 0; | ||
window_class.lpszMenuName = nullptr; | ||
window_class.lpfnWndProc = WndProc; | ||
RegisterClass(&window_class); | ||
return window_class; | ||
} | ||
|
||
LRESULT | ||
TaskRunnerWin32Window::HandleMessage(UINT const message, | ||
WPARAM const wparam, | ||
LPARAM const lparam) noexcept { | ||
switch (message) { | ||
case WM_TIMER: | ||
case WM_NULL: | ||
ProcessTasks(); | ||
return 0; | ||
} | ||
return DefWindowProcW(window_handle_, message, wparam, lparam); | ||
} | ||
|
||
LRESULT TaskRunnerWin32Window::WndProc(HWND const window, | ||
UINT const message, | ||
WPARAM const wparam, | ||
LPARAM const lparam) noexcept { | ||
if (auto* that = reinterpret_cast<TaskRunnerWin32Window*>( | ||
GetWindowLongPtr(window, GWLP_USERDATA))) { | ||
return that->HandleMessage(message, wparam, lparam); | ||
} else { | ||
return DefWindowProc(window, message, wparam, lparam); | ||
} | ||
} | ||
|
||
} // namespace flutter |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_WINDOW_H_ | ||
#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_WINDOW_H_ | ||
|
||
#include <windows.h> | ||
|
||
#include <chrono> | ||
#include <memory> | ||
#include <string> | ||
#include <vector> | ||
|
||
namespace flutter { | ||
|
||
// Hidden HWND responsible for processing flutter tasks on main thread | ||
class TaskRunnerWin32Window { | ||
public: | ||
class Delegate { | ||
public: | ||
virtual std::chrono::nanoseconds ProcessTasks() = 0; | ||
}; | ||
|
||
static std::shared_ptr<TaskRunnerWin32Window> GetSharedInstance(); | ||
|
||
// Triggers processing delegate tasks on main thread | ||
void WakeUp(); | ||
|
||
void AddDelegate(Delegate* delegate); | ||
void RemoveDelegate(Delegate* delegate); | ||
|
||
~TaskRunnerWin32Window(); | ||
|
||
private: | ||
TaskRunnerWin32Window(); | ||
|
||
void ProcessTasks(); | ||
|
||
void SetTimer(std::chrono::nanoseconds when); | ||
|
||
WNDCLASS RegisterWindowClass(); | ||
|
||
LRESULT | ||
HandleMessage(UINT const message, | ||
WPARAM const wparam, | ||
LPARAM const lparam) noexcept; | ||
|
||
static LRESULT CALLBACK WndProc(HWND const window, | ||
UINT const message, | ||
WPARAM const wparam, | ||
LPARAM const lparam) noexcept; | ||
|
||
HWND window_handle_; | ||
std::wstring window_class_name_; | ||
std::vector<Delegate*> delegates_; | ||
}; | ||
} // namespace flutter | ||
|
||
#endif |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we even need FlutterDesktopEngineProcessMessages any more with this change. I don't believe we use it in UWP. It would be a breaking change tho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not necessary anymore (it a noop that just returns -1). Next step would be to remove this from the Windows template (it would become simple Get/Translate/Dispatch message loop). Returning -1 ensures that existing run-loops work just fine after the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually removing the function would involve writing a migrator into the Flutter tool. (There's some infrastructure in the tooling for it, but it hasn't been used yet on Windows)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stuartmorgan, I don't think I'd want to remove the function from API anytime soon, but the template can be significantly simplified. I'll look at the migration, but that should not block this PR, right?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, both this PR and a template upgrade are non-breaking, so aren't blocked. It's only at the point where it would actually be removed that a migrator would be necessary.