@@ -61,55 +61,88 @@ applyPositioner(flutter::FlutterWindowPositioner const& positioner,
61
61
return GetMonitorInfo (monitor, &mi) ? mi.rcMonitor : RECT{0 , 0 , 0 , 0 };
62
62
}(parent_hwnd)};
63
63
64
- RECT frame;
65
- if (FAILED (DwmGetWindowAttribute (parent_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS,
66
- &frame, sizeof (frame)))) {
67
- GetWindowRect (parent_hwnd, &frame);
68
- }
69
-
70
64
struct RectF {
71
65
double left;
72
66
double top;
73
67
double right;
74
68
double bottom;
75
69
};
76
-
77
70
struct PointF {
78
71
double x;
79
72
double y;
80
73
};
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 };
91
124
PointF child_size{size.width * dpr, size.height * dpr};
92
125
PointF const child_center{child_size.x / 2.0 , child_size.y / 2.0 };
93
126
94
127
auto const get_parent_anchor_point{
95
128
[&](flutter::FlutterWindowPositioner::Anchor anchor) -> PointF {
96
129
switch (anchor) {
97
130
case flutter::FlutterWindowPositioner::Anchor::top:
98
- return {center.x , cropped_frame .top };
131
+ return {center.x , anchor_rect .top };
99
132
case flutter::FlutterWindowPositioner::Anchor::bottom:
100
- return {center.x , cropped_frame .bottom };
133
+ return {center.x , anchor_rect .bottom };
101
134
case flutter::FlutterWindowPositioner::Anchor::left:
102
- return {cropped_frame .left , center.y };
135
+ return {anchor_rect .left , center.y };
103
136
case flutter::FlutterWindowPositioner::Anchor::right:
104
- return {cropped_frame .right , center.y };
137
+ return {anchor_rect .right , center.y };
105
138
case flutter::FlutterWindowPositioner::Anchor::top_left:
106
- return {cropped_frame .left , cropped_frame .top };
139
+ return {anchor_rect .left , anchor_rect .top };
107
140
case flutter::FlutterWindowPositioner::Anchor::bottom_left:
108
- return {cropped_frame .left , cropped_frame .bottom };
141
+ return {anchor_rect .left , anchor_rect .bottom };
109
142
case flutter::FlutterWindowPositioner::Anchor::top_right:
110
- return {cropped_frame .right , cropped_frame .top };
143
+ return {anchor_rect .right , anchor_rect .top };
111
144
case flutter::FlutterWindowPositioner::Anchor::bottom_right:
112
- return {cropped_frame .right , cropped_frame .bottom };
145
+ return {anchor_rect .right , anchor_rect .bottom };
113
146
default :
114
147
return center;
115
148
}
@@ -493,22 +526,29 @@ void handleCreatePopupWindow(flutter::MethodCall<> const& call,
493
526
static_cast <unsigned int >(height)};
494
527
495
528
// 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 ))};
507
551
}
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 ))};
512
552
513
553
// positionerParentAnchor
514
554
auto const * const positioner_parent_anchor{
@@ -582,10 +622,7 @@ void handleCreatePopupWindow(flutter::MethodCall<> const& call,
582
622
}
583
623
584
624
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,
589
626
.anchor = static_cast <flutter::FlutterWindowPositioner::Anchor>(
590
627
*positioner_parent_anchor),
591
628
.gravity = gravity,
0 commit comments