@@ -61,55 +61,88 @@ applyPositioner(flutter::FlutterWindowPositioner const& positioner,
6161 return GetMonitorInfo (monitor, &mi) ? mi.rcMonitor : RECT{0 , 0 , 0 , 0 };
6262 }(parent_hwnd)};
6363
64- RECT frame;
65- if (FAILED (DwmGetWindowAttribute (parent_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS,
66- &frame, sizeof (frame)))) {
67- GetWindowRect (parent_hwnd, &frame);
68- }
69-
7064 struct RectF {
7165 double left;
7266 double top;
7367 double right;
7468 double bottom;
7569 };
76-
7770 struct PointF {
7871 double x;
7972 double y;
8073 };
81- RectF const cropped_frame{
82- .left = frame.left + positioner.anchor_rect .x * dpr,
83- .top = frame.top + positioner.anchor_rect .y * dpr,
84- .right = frame.left +
85- (positioner.anchor_rect .x + positioner.anchor_rect .width ) * dpr,
86- .bottom =
87- frame.top +
88- (positioner.anchor_rect .y + positioner.anchor_rect .height ) * dpr};
89- PointF const center{.x = (cropped_frame.left + cropped_frame.right ) / 2.0 ,
90- .y = (cropped_frame.top + cropped_frame.bottom ) / 2.0 };
74+
75+ auto const anchor_rect{[&]() -> RectF {
76+ if (positioner.anchor_rect ) {
77+ // If the positioner's anchor rect is not std::nullopt, use it to anchor
78+ // relative to the client area
79+ RECT rect;
80+ GetClientRect (parent_hwnd, &rect);
81+ POINT top_left{rect.left , rect.top };
82+ ClientToScreen (parent_hwnd, &top_left);
83+ POINT bottom_right{rect.right , rect.bottom };
84+ ClientToScreen (parent_hwnd, &bottom_right);
85+
86+ RectF anchor_rect_screen_space{
87+ .left = top_left.x + positioner.anchor_rect ->x * dpr,
88+ .top = top_left.y + positioner.anchor_rect ->y * dpr,
89+ .right =
90+ top_left.x +
91+ (positioner.anchor_rect ->x + positioner.anchor_rect ->width ) * dpr,
92+ .bottom = top_left.y + (positioner.anchor_rect ->y +
93+ positioner.anchor_rect ->height ) *
94+ dpr};
95+ // Ensure the anchor rect stays within the bounds of the client rect
96+ anchor_rect_screen_space.left = std::clamp (
97+ anchor_rect_screen_space.left , static_cast <double >(top_left.x ),
98+ static_cast <double >(bottom_right.x ));
99+ anchor_rect_screen_space.top = std::clamp (
100+ anchor_rect_screen_space.top , static_cast <double >(top_left.y ),
101+ static_cast <double >(bottom_right.y ));
102+ anchor_rect_screen_space.right = std::clamp (
103+ anchor_rect_screen_space.right , static_cast <double >(top_left.x ),
104+ static_cast <double >(bottom_right.x ));
105+ anchor_rect_screen_space.bottom = std::clamp (
106+ anchor_rect_screen_space.bottom , static_cast <double >(top_left.y ),
107+ static_cast <double >(bottom_right.y ));
108+ return anchor_rect_screen_space;
109+ } else {
110+ // If the positioner's anchor rect is std::nullopt, create an anchor rect
111+ // that is equal to the window frame area
112+ RECT frame_rect;
113+ DwmGetWindowAttribute (parent_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS,
114+ &frame_rect, sizeof (frame_rect));
115+ return {static_cast <double >(frame_rect.left ),
116+ static_cast <double >(frame_rect.top ),
117+ static_cast <double >(frame_rect.right ),
118+ static_cast <double >(frame_rect.bottom )};
119+ }
120+ }()};
121+
122+ PointF const center{.x = (anchor_rect.left + anchor_rect.right ) / 2.0 ,
123+ .y = (anchor_rect.top + anchor_rect.bottom ) / 2.0 };
91124 PointF child_size{size.width * dpr, size.height * dpr};
92125 PointF const child_center{child_size.x / 2.0 , child_size.y / 2.0 };
93126
94127 auto const get_parent_anchor_point{
95128 [&](flutter::FlutterWindowPositioner::Anchor anchor) -> PointF {
96129 switch (anchor) {
97130 case flutter::FlutterWindowPositioner::Anchor::top:
98- return {center.x , cropped_frame .top };
131+ return {center.x , anchor_rect .top };
99132 case flutter::FlutterWindowPositioner::Anchor::bottom:
100- return {center.x , cropped_frame .bottom };
133+ return {center.x , anchor_rect .bottom };
101134 case flutter::FlutterWindowPositioner::Anchor::left:
102- return {cropped_frame .left , center.y };
135+ return {anchor_rect .left , center.y };
103136 case flutter::FlutterWindowPositioner::Anchor::right:
104- return {cropped_frame .right , center.y };
137+ return {anchor_rect .right , center.y };
105138 case flutter::FlutterWindowPositioner::Anchor::top_left:
106- return {cropped_frame .left , cropped_frame .top };
139+ return {anchor_rect .left , anchor_rect .top };
107140 case flutter::FlutterWindowPositioner::Anchor::bottom_left:
108- return {cropped_frame .left , cropped_frame .bottom };
141+ return {anchor_rect .left , anchor_rect .bottom };
109142 case flutter::FlutterWindowPositioner::Anchor::top_right:
110- return {cropped_frame .right , cropped_frame .top };
143+ return {anchor_rect .right , anchor_rect .top };
111144 case flutter::FlutterWindowPositioner::Anchor::bottom_right:
112- return {cropped_frame .right , cropped_frame .bottom };
145+ return {anchor_rect .right , anchor_rect .bottom };
113146 default :
114147 return center;
115148 }
@@ -493,22 +526,29 @@ void handleCreatePopupWindow(flutter::MethodCall<> const& call,
493526 static_cast <unsigned int >(height)};
494527
495528 // anchorRect
496- auto const * const anchor_rect_list{
497- std::get_if<std::vector<flutter::EncodableValue>>(
498- &anchor_rect_it->second )};
499- if (anchor_rect_list->size () != 4 ||
500- !std::holds_alternative<int >(anchor_rect_list->at (0 )) ||
501- !std::holds_alternative<int >(anchor_rect_list->at (1 )) ||
502- !std::holds_alternative<int >(anchor_rect_list->at (2 )) ||
503- !std::holds_alternative<int >(anchor_rect_list->at (3 ))) {
504- result->Error (" INVALID_VALUE" ,
505- " Values for 'anchorRect' must be of type int." );
506- return ;
529+ std::optional<flutter::FlutterWindowPositioner::Rect> anchor_rect;
530+ if (auto const * const anchor_rect_list{
531+ std::get_if<std::vector<flutter::EncodableValue>>(
532+ &anchor_rect_it->second )}) {
533+ if (anchor_rect_list->size () != 4 ) {
534+ result->Error (
535+ " INVALID_VALUE" ,
536+ " Values for 'anchorRect' must be an array of 4 integers." );
537+ return ;
538+ } else if (!std::holds_alternative<int >(anchor_rect_list->at (0 )) ||
539+ !std::holds_alternative<int >(anchor_rect_list->at (1 )) ||
540+ !std::holds_alternative<int >(anchor_rect_list->at (2 )) ||
541+ !std::holds_alternative<int >(anchor_rect_list->at (3 ))) {
542+ result->Error (" INVALID_VALUE" ,
543+ " Values for 'anchorRect' must be of type int." );
544+ return ;
545+ }
546+ anchor_rect = flutter::FlutterWindowPositioner::Rect{
547+ .x = std::get<int >(anchor_rect_list->at (0 )),
548+ .y = std::get<int >(anchor_rect_list->at (1 )),
549+ .width = std::get<int >(anchor_rect_list->at (2 )),
550+ .height = std::get<int >(anchor_rect_list->at (3 ))};
507551 }
508- auto const anchor_rect_x{std::get<int >(anchor_rect_list->at (0 ))};
509- auto const anchor_rect_y{std::get<int >(anchor_rect_list->at (1 ))};
510- auto const anchor_rect_width{std::get<int >(anchor_rect_list->at (2 ))};
511- auto const anchor_rect_height{std::get<int >(anchor_rect_list->at (3 ))};
512552
513553 // positionerParentAnchor
514554 auto const * const positioner_parent_anchor{
@@ -582,10 +622,7 @@ void handleCreatePopupWindow(flutter::MethodCall<> const& call,
582622 }
583623
584624 flutter::FlutterWindowPositioner const positioner{
585- .anchor_rect = {.x = anchor_rect_x,
586- .y = anchor_rect_y,
587- .width = anchor_rect_width,
588- .height = anchor_rect_height},
625+ .anchor_rect = anchor_rect,
589626 .anchor = static_cast <flutter::FlutterWindowPositioner::Anchor>(
590627 *positioner_parent_anchor),
591628 .gravity = gravity,
0 commit comments