5#include "flutter/shell/platform/windows/cursor_handler.h"
9#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
10#include "flutter/shell/platform/windows/flutter_windows_engine.h"
11#include "flutter/shell/platform/windows/flutter_windows_view.h"
21 "createCustomCursor/windows";
43 "deleteCustomCursor/windows";
57 channel_->SetMethodCallHandler(
64void CursorHandler::HandleMethodCall(
67 const std::string& method =
method_call.method_name();
69 const auto& arguments = std::get<EncodableMap>(*
method_call.arguments());
71 if (kind_iter == arguments.end()) {
72 result->Error(
"Argument error",
73 "Missing argument while trying to activate system cursor");
76 const auto& kind = std::get<std::string>(kind_iter->second);
81 if (view ==
nullptr) {
83 "Cursor is not available in Windows headless mode");
86 view->UpdateFlutterCursor(kind);
89 const auto& arguments = std::get<EncodableMap>(*
method_call.arguments());
92 if (name_iter == arguments.end()) {
95 "Missing argument name while trying to customize system cursor");
98 auto name = std::get<std::string>(name_iter->second);
101 if (buffer_iter == arguments.end()) {
104 "Missing argument buffer while trying to customize system cursor");
107 auto buffer = std::get<std::vector<uint8_t>>(buffer_iter->second);
110 if (width_iter == arguments.end()) {
113 "Missing argument width while trying to customize system cursor");
116 auto width = std::get<int>(width_iter->second);
119 if (height_iter == arguments.end()) {
122 "Missing argument height while trying to customize system cursor");
125 auto height = std::get<int>(height_iter->second);
128 if (hot_x_iter == arguments.end()) {
131 "Missing argument hotX while trying to customize system cursor");
134 auto hot_x = std::get<double>(hot_x_iter->second);
137 if (hot_y_iter == arguments.end()) {
140 "Missing argument hotY while trying to customize system cursor");
143 auto hot_y = std::get<double>(hot_y_iter->second);
145 if (cursor ==
nullptr) {
146 result->Error(
"Argument error",
147 "Argument must contains a valid rawBGRA bitmap");
151 custom_cursors_.emplace(
name, std::move(cursor));
154 const auto& arguments = std::get<EncodableMap>(*
method_call.arguments());
157 if (name_iter == arguments.end()) {
158 result->Error(
"Argument error",
159 "Missing argument key while trying to set a custom cursor");
162 auto name = std::get<std::string>(name_iter->second);
163 if (custom_cursors_.find(
name) == custom_cursors_.end()) {
166 "The custom cursor identified by the argument key cannot be found");
169 HCURSOR cursor = custom_cursors_[
name];
174 if (view ==
nullptr) {
176 "Cursor is not available in Windows headless mode");
179 view->SetFlutterCursor(cursor);
182 const auto& arguments = std::get<EncodableMap>(*
method_call.arguments());
185 if (name_iter == arguments.end()) {
188 "Missing argument key while trying to delete a custom cursor");
191 auto name = std::get<std::string>(name_iter->second);
192 auto it = custom_cursors_.find(
name);
195 if (it != custom_cursors_.end()) {
196 DeleteObject(it->second);
197 custom_cursors_.erase(it);
210 HCURSOR cursor =
nullptr;
211 HDC display_dc = GetDC(NULL);
214 memset(&bmi, 0,
sizeof(bmi));
215 bmi.bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
216 bmi.bmiHeader.biWidth =
width;
217 bmi.bmiHeader.biHeight = -
height;
218 bmi.bmiHeader.biPlanes = 1;
219 bmi.bmiHeader.biBitCount = 32;
220 bmi.bmiHeader.biCompression = BI_RGB;
225 CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (
void**)&pixels, 0, 0);
226 ReleaseDC(0, display_dc);
230 int bytes_per_line =
width * 4;
232 memcpy(pixels +
y * bytes_per_line, &
buffer[bytes_per_line *
y],
239 icon_info.xHotspot = hot_x;
240 icon_info.yHotspot = hot_y;
241 icon_info.hbmMask = mask;
242 icon_info.hbmColor =
bitmap;
243 cursor = CreateIconIndirect(&icon_info);
250 HDC h_dc = ::GetDC(NULL);
251 HDC h_main_dc = ::CreateCompatibleDC(h_dc);
252 HDC h_and_mask_dc = ::CreateCompatibleDC(h_dc);
257 mask_bitmap = ::CreateCompatibleBitmap(h_dc, bm.bmWidth, bm.bmHeight);
260 HBITMAP h_old_main_bitmap = (HBITMAP)::SelectObject(h_main_dc,
bitmap);
261 HBITMAP h_old_and_mask_bitmap =
262 (HBITMAP)::SelectObject(h_and_mask_dc, mask_bitmap);
265 COLORREF main_bit_pixel;
266 for (
int x = 0;
x < bm.bmWidth; ++
x) {
267 for (
int y = 0;
y < bm.bmHeight; ++
y) {
268 main_bit_pixel = ::GetPixel(h_main_dc,
x,
y);
269 if (main_bit_pixel == RGB(0, 0, 0)) {
270 ::SetPixel(h_and_mask_dc,
x,
y, RGB(255, 255, 255));
272 ::SetPixel(h_and_mask_dc,
x,
y, RGB(0, 0, 0));
276 ::SelectObject(h_main_dc, h_old_main_bitmap);
277 ::SelectObject(h_and_mask_dc, h_old_and_mask_bitmap);
279 ::DeleteDC(h_and_mask_dc);
280 ::DeleteDC(h_main_dc);
282 ::ReleaseDC(NULL, h_dc);
CursorHandler(flutter::BinaryMessenger *messenger, flutter::FlutterWindowsEngine *engine)
FlutterWindowsView * view(FlutterViewId view_id) const
static constexpr char kDeleteCustomCursorMethod[]
static constexpr char kActivateSystemCursorMethod[]
static constexpr char kCustomCursorHotXKey[]
static constexpr char kCustomCursorWidthKey[]
static constexpr char kKindKey[]
static constexpr char kChannelName[]
static constexpr char kCustomCursorHotYKey[]
static constexpr char kCustomCursorNameKey[]
static constexpr char kCreateCustomCursorMethod[]
static constexpr char kSetCustomCursorMethod[]
static constexpr char kCustomCursorBufferKey[]
static constexpr char kCursorError[]
static constexpr char kCustomCursorHeightKey[]
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
static void GetObject(Thread *thread, JSONStream *js)
void GetMaskBitmaps(HBITMAP bitmap, HBITMAP &mask_bitmap)
DEF_SWITCHES_START aot vmservice shared library name
constexpr FlutterViewId kImplicitViewId
HCURSOR GetCursorFromBuffer(const std::vector< uint8_t > &buffer, double hot_x, double hot_y, int width, int height)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer