Skip to content

Commit b2adf74

Browse files
authored
[Windows] Allow plugins to get views (flutter#51096)
Allow Flutter Windows plugins to get views by their ID. Design doc: https://flutter.dev/go/desktop-multi-view-runner-apis Part of flutter/flutter#143767 Part of flutter/flutter#142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 31bbe61 commit b2adf74

File tree

9 files changed

+180
-20
lines changed

9 files changed

+180
-20
lines changed

shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class PluginRegistrar {
5454
void AddPlugin(std::unique_ptr<Plugin> plugin);
5555

5656
protected:
57-
FlutterDesktopPluginRegistrarRef registrar() { return registrar_; }
57+
FlutterDesktopPluginRegistrarRef registrar() const { return registrar_; }
5858

5959
// Destroys all owned plugins. Subclasses should call this at the beginning of
6060
// their destructors to prevent the possibility of an owned plugin trying to

shell/platform/windows/client_wrapper/include/flutter/flutter_view.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class FlutterView {
1717
public:
1818
explicit FlutterView(FlutterDesktopViewRef view) : view_(view) {}
1919

20+
// Destroys this reference to the view. The underlying view is not destroyed.
2021
virtual ~FlutterView() = default;
2122

2223
// Prevent copying.

shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,45 @@ class PluginRegistrarWindows : public PluginRegistrar {
3232
explicit PluginRegistrarWindows(
3333
FlutterDesktopPluginRegistrarRef core_registrar)
3434
: PluginRegistrar(core_registrar) {
35-
view_ = std::make_unique<FlutterView>(
36-
FlutterDesktopPluginRegistrarGetView(core_registrar));
35+
FlutterDesktopViewRef implicit_view =
36+
FlutterDesktopPluginRegistrarGetView(core_registrar);
37+
if (implicit_view) {
38+
implicit_view_ = std::make_unique<FlutterView>(implicit_view);
39+
}
3740
}
3841

3942
virtual ~PluginRegistrarWindows() {
4043
// Must be the first call.
4144
ClearPlugins();
4245
// Explicitly cleared to facilitate destruction order testing.
43-
view_.reset();
46+
implicit_view_.reset();
4447
}
4548

4649
// Prevent copying.
4750
PluginRegistrarWindows(PluginRegistrarWindows const&) = delete;
4851
PluginRegistrarWindows& operator=(PluginRegistrarWindows const&) = delete;
4952

50-
FlutterView* GetView() { return view_.get(); }
53+
// Returns the implicit view, or nullptr if there is no implicit view.
54+
//
55+
// See:
56+
// https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html
57+
//
58+
// DEPRECATED: Use |GetViewById| instead.
59+
FlutterView* GetView() { return implicit_view_.get(); }
60+
61+
// Returns the view with the given ID, or nullptr if the view does not exist.
62+
//
63+
// Destroying the shared pointer destroys the reference to the view; it does
64+
// not destroy the underlying view.
65+
std::shared_ptr<FlutterView> GetViewById(FlutterViewId view_id) const {
66+
FlutterDesktopViewRef view =
67+
FlutterDesktopPluginRegistrarGetViewById(registrar(), view_id);
68+
if (!view) {
69+
return nullptr;
70+
}
71+
72+
return std::make_shared<FlutterView>(view);
73+
}
5174

5275
// Registers |delegate| to receive WindowProc callbacks for the top-level
5376
// window containing this Flutter instance. Returns an ID that can be used to
@@ -115,7 +138,7 @@ class PluginRegistrarWindows : public PluginRegistrar {
115138
}
116139

117140
// The associated FlutterView, if any.
118-
std::unique_ptr<FlutterView> view_;
141+
std::unique_ptr<FlutterView> implicit_view_;
119142

120143
// The next ID to return from RegisterWindowProcDelegate.
121144
int next_window_proc_delegate_id_ = 1;

shell/platform/windows/client_wrapper/plugin_registrar_windows_unittests.cc

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77

88
#include "flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h"
99
#include "flutter/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h"
10+
#include "gmock/gmock.h"
1011
#include "gtest/gtest.h"
1112

1213
namespace flutter {
1314

1415
namespace {
1516

17+
using ::testing::Return;
18+
1619
// Stub implementation to validate calls to the API.
1720
class TestWindowsApi : public testing::StubFlutterWindowsApi {
1821
public:
@@ -24,6 +27,12 @@ class TestWindowsApi : public testing::StubFlutterWindowsApi {
2427
last_registered_user_data_ = user_data;
2528
}
2629

30+
MOCK_METHOD(FlutterDesktopViewRef, PluginRegistrarGetView, (), (override));
31+
MOCK_METHOD(FlutterDesktopViewRef,
32+
PluginRegistrarGetViewById,
33+
(FlutterDesktopViewId),
34+
(override));
35+
2736
void PluginRegistrarUnregisterTopLevelWindowProcDelegate(
2837
FlutterDesktopWindowProcCallback delegate) override {
2938
--registered_delegate_count_;
@@ -65,16 +74,47 @@ class TestPlugin : public Plugin {
6574
} // namespace
6675

6776
TEST(PluginRegistrarWindowsTest, GetView) {
68-
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
69-
std::make_unique<TestWindowsApi>());
77+
auto windows_api = std::make_unique<TestWindowsApi>();
78+
EXPECT_CALL(*windows_api, PluginRegistrarGetView)
79+
.WillOnce(Return(reinterpret_cast<FlutterDesktopViewRef>(1)));
80+
81+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
7082
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
7183
PluginRegistrarWindows registrar(
7284
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
85+
7386
EXPECT_NE(registrar.GetView(), nullptr);
7487
}
7588

89+
TEST(PluginRegistrarWindowsTest, GetViewById) {
90+
auto windows_api = std::make_unique<TestWindowsApi>();
91+
EXPECT_CALL(*windows_api, PluginRegistrarGetView)
92+
.WillRepeatedly(Return(nullptr));
93+
EXPECT_CALL(*windows_api, PluginRegistrarGetViewById(123))
94+
.WillOnce(Return(reinterpret_cast<FlutterDesktopViewRef>(1)));
95+
EXPECT_CALL(*windows_api, PluginRegistrarGetViewById(456))
96+
.WillOnce(Return(nullptr));
97+
98+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
99+
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
100+
PluginRegistrarWindows registrar(
101+
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
102+
103+
EXPECT_EQ(registrar.GetView(), nullptr);
104+
EXPECT_NE(registrar.GetViewById(123).get(), nullptr);
105+
EXPECT_EQ(registrar.GetViewById(456).get(), nullptr);
106+
}
107+
76108
// Tests that the registrar runs plugin destructors before its own teardown.
77109
TEST(PluginRegistrarWindowsTest, PluginDestroyedBeforeRegistrar) {
110+
auto windows_api = std::make_unique<TestWindowsApi>();
111+
EXPECT_CALL(*windows_api, PluginRegistrarGetView)
112+
.WillRepeatedly(Return(reinterpret_cast<FlutterDesktopViewRef>(1)));
113+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
114+
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
115+
PluginRegistrarWindows registrar(
116+
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
117+
78118
auto dummy_registrar_handle =
79119
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1);
80120
bool registrar_valid_at_destruction = false;
@@ -89,8 +129,9 @@ TEST(PluginRegistrarWindowsTest, PluginDestroyedBeforeRegistrar) {
89129
}
90130

91131
TEST(PluginRegistrarWindowsTest, RegisterUnregister) {
92-
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
93-
std::make_unique<TestWindowsApi>());
132+
auto windows_api = std::make_unique<TestWindowsApi>();
133+
EXPECT_CALL(*windows_api, PluginRegistrarGetView).WillOnce(Return(nullptr));
134+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
94135
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
95136
PluginRegistrarWindows registrar(
96137
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
@@ -118,8 +159,9 @@ TEST(PluginRegistrarWindowsTest, RegisterUnregister) {
118159
}
119160

120161
TEST(PluginRegistrarWindowsTest, CallsRegisteredDelegates) {
121-
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
122-
std::make_unique<TestWindowsApi>());
162+
auto windows_api = std::make_unique<TestWindowsApi>();
163+
EXPECT_CALL(*windows_api, PluginRegistrarGetView).WillOnce(Return(nullptr));
164+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
123165
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
124166
PluginRegistrarWindows registrar(
125167
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
@@ -154,8 +196,9 @@ TEST(PluginRegistrarWindowsTest, CallsRegisteredDelegates) {
154196
}
155197

156198
TEST(PluginRegistrarWindowsTest, StopsOnceHandled) {
157-
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
158-
std::make_unique<TestWindowsApi>());
199+
auto windows_api = std::make_unique<TestWindowsApi>();
200+
EXPECT_CALL(*windows_api, PluginRegistrarGetView).WillOnce(Return(nullptr));
201+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
159202
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
160203
PluginRegistrarWindows registrar(
161204
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));

shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,19 @@ void FlutterDesktopEngineRegisterPlatformViewType(
194194

195195
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
196196
FlutterDesktopPluginRegistrarRef controller) {
197-
// The stub ignores this, so just return an arbitrary non-zero value.
198-
return reinterpret_cast<FlutterDesktopViewRef>(1);
197+
if (s_stub_implementation) {
198+
return s_stub_implementation->PluginRegistrarGetView();
199+
}
200+
return nullptr;
201+
}
202+
203+
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById(
204+
FlutterDesktopPluginRegistrarRef controller,
205+
FlutterDesktopViewId view_id) {
206+
if (s_stub_implementation) {
207+
return s_stub_implementation->PluginRegistrarGetViewById(view_id);
208+
}
209+
return nullptr;
199210
}
200211

201212
void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(

shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ class StubFlutterWindowsApi {
8686
return reinterpret_cast<IDXGIAdapter*>(2);
8787
}
8888

89+
// Called for FlutterDesktopPluginRegistrarGetView.
90+
virtual FlutterDesktopViewRef PluginRegistrarGetView() { return nullptr; }
91+
92+
// Called for FlutterDesktopPluginRegistrarGetViewById.
93+
virtual FlutterDesktopViewRef PluginRegistrarGetViewById(
94+
FlutterDesktopViewId view_id) {
95+
return nullptr;
96+
}
97+
8998
// Called for FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate.
9099
virtual void PluginRegistrarRegisterTopLevelWindowProcDelegate(
91100
FlutterDesktopWindowProcCallback delegate,

shell/platform/windows/flutter_windows.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,12 +261,15 @@ void FlutterDesktopEngineRegisterPlatformViewType(
261261

262262
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
263263
FlutterDesktopPluginRegistrarRef registrar) {
264-
// TODO(loicsharma): Add |FlutterDesktopPluginRegistrarGetViewById| and
265-
// deprecate this API as it makes single view assumptions.
266-
// https://github.com/flutter/flutter/issues/143767
267264
return HandleForView(registrar->engine->view(flutter::kImplicitViewId));
268265
}
269266

267+
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById(
268+
FlutterDesktopPluginRegistrarRef registrar,
269+
FlutterDesktopViewId view_id) {
270+
return HandleForView(registrar->engine->view(view_id));
271+
}
272+
270273
void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(
271274
FlutterDesktopPluginRegistrarRef registrar,
272275
FlutterDesktopWindowProcCallback delegate,

shell/platform/windows/flutter_windows_unittests.cc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,64 @@ TEST_F(WindowsTest, GetGraphicsAdapter) {
333333
ASSERT_TRUE(SUCCEEDED(dxgi_adapter->GetDesc(&desc)));
334334
}
335335

336+
// Implicit view has the implicit view ID.
337+
TEST_F(WindowsTest, PluginRegistrarGetImplicitView) {
338+
auto& context = GetContext();
339+
WindowsConfigBuilder builder(context);
340+
ViewControllerPtr controller{builder.Run()};
341+
ASSERT_NE(controller, nullptr);
342+
343+
FlutterDesktopEngineRef engine =
344+
FlutterDesktopViewControllerGetEngine(controller.get());
345+
FlutterDesktopPluginRegistrarRef registrar =
346+
FlutterDesktopEngineGetPluginRegistrar(engine, "foo_bar");
347+
FlutterDesktopViewRef implicit_view =
348+
FlutterDesktopPluginRegistrarGetView(registrar);
349+
350+
ASSERT_NE(implicit_view, nullptr);
351+
}
352+
353+
TEST_F(WindowsTest, PluginRegistrarGetView) {
354+
auto& context = GetContext();
355+
WindowsConfigBuilder builder(context);
356+
ViewControllerPtr controller{builder.Run()};
357+
ASSERT_NE(controller, nullptr);
358+
359+
FlutterDesktopEngineRef engine =
360+
FlutterDesktopViewControllerGetEngine(controller.get());
361+
FlutterDesktopPluginRegistrarRef registrar =
362+
FlutterDesktopEngineGetPluginRegistrar(engine, "foo_bar");
363+
364+
FlutterDesktopViewId view_id =
365+
FlutterDesktopViewControllerGetViewId(controller.get());
366+
FlutterDesktopViewRef view =
367+
FlutterDesktopPluginRegistrarGetViewById(registrar, view_id);
368+
369+
FlutterDesktopViewRef view_123 = FlutterDesktopPluginRegistrarGetViewById(
370+
registrar, static_cast<FlutterDesktopViewId>(123));
371+
372+
ASSERT_NE(view, nullptr);
373+
ASSERT_EQ(view_123, nullptr);
374+
}
375+
376+
TEST_F(WindowsTest, PluginRegistrarGetViewHeadless) {
377+
auto& context = GetContext();
378+
WindowsConfigBuilder builder(context);
379+
EnginePtr engine{builder.RunHeadless()};
380+
ASSERT_NE(engine, nullptr);
381+
382+
FlutterDesktopPluginRegistrarRef registrar =
383+
FlutterDesktopEngineGetPluginRegistrar(engine.get(), "foo_bar");
384+
385+
FlutterDesktopViewRef implicit_view =
386+
FlutterDesktopPluginRegistrarGetView(registrar);
387+
FlutterDesktopViewRef view_123 = FlutterDesktopPluginRegistrarGetViewById(
388+
registrar, static_cast<FlutterDesktopViewId>(123));
389+
390+
ASSERT_EQ(implicit_view, nullptr);
391+
ASSERT_EQ(view_123, nullptr);
392+
}
393+
336394
// Verify the app does not crash if EGL initializes successfully but
337395
// the rendering surface cannot be created.
338396
TEST_F(WindowsTest, SurfaceOptional) {

shell/platform/windows/public/flutter_windows.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,22 @@ typedef bool (*FlutterDesktopWindowProcCallback)(HWND /* hwnd */,
249249
void* /* user data */,
250250
LRESULT* result);
251251

252-
// Returns the view associated with this registrar's engine instance.
252+
// Returns the implicit view associated with this registrar's engine instance,
253+
// or null if there is no implicit view.
254+
//
255+
// See:
256+
// https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html
257+
//
258+
// DEPRECATED: Use |FlutterDesktopPluginRegistrarGetViewById| instead.
253259
FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
254260
FlutterDesktopPluginRegistrarRef registrar);
255261

262+
// Returns the view associated with the registrar's engine instance, or null if
263+
// the view does not exist.
264+
FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById(
265+
FlutterDesktopPluginRegistrarRef registrar,
266+
FlutterDesktopViewId view_id);
267+
256268
FLUTTER_EXPORT void
257269
FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(
258270
FlutterDesktopPluginRegistrarRef registrar,

0 commit comments

Comments
 (0)