Fix #109194: window decorations mismatch on startup under Wayland

Workaround for multiple monitors with different scaling causing
the window frame not to match the window contents on startup with GNOME.
This commit is contained in:
Campbell Barton
2023-12-17 17:05:18 +11:00
parent 950334a02c
commit f845a3992c

View File

@@ -2382,6 +2382,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
window_->frame.fractional_scale :
window_->frame.buffer_scale * FRACTIONAL_DENOMINATOR;
int scale_prev = fractional_scale_prev / FRACTIONAL_DENOMINATOR;
bool do_frame_resize = true;
if (window_->frame_pending.is_scale_init == false) {
window_->frame_pending.is_scale_init = true;
@@ -2392,13 +2393,56 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
*
* To support anything more sophisticated, windows would need to be created with a scale
* argument (representing the scale used when the window was stored, for e.g.). */
is_fractional_prev = is_fractional_next;
scale_prev = scale_next;
fractional_scale_prev = fractional_scale_next;
/* Leave `window_->frame_pending` as-is, so changes are detected and updates are applied. */
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
/* LIBDECOR needs it's own logic, failing to do this causes the window border
* not to follow the GHOST window on startup - with multiple monitors,
* each with different fractional scale, see: #109194.
*
* Note that the window will show larger, then resize to be smaller soon
* after opening, this would be nice to avoid but but would require DPI
* to be stored in the window (as noted above). */
int size_next[2] = {0, 0};
int size_orig[2] = {0, 0};
force_frame_update = true;
/* Leave `window_->frame_pending` as-is, only change the window frame. */
for (size_t i = 0; i < ARRAY_SIZE(window_->frame_pending.size); i++) {
const int value = size_next[i] ? window_->frame_pending.size[i] : window_->frame.size[i];
size_orig[i] = value;
if (is_fractional_prev || is_fractional_next) {
size_next[i] = lroundf((value * double(FRACTIONAL_DENOMINATOR)) /
double(fractional_scale_next));
}
else {
window_->frame_pending.size[i] = value / scale_prev;
}
if (window_->frame_pending.buffer_scale > 1) {
gwl_round_int_by(&size_next[i], window_->frame_pending.buffer_scale);
}
}
if (size_orig[0] != size_next[0] || size_orig[1] != size_next[1]) {
GWL_LibDecor_Window &decor = *window_->libdecor;
libdecor_state *state = libdecor_state_new(UNPACK2(size_next));
libdecor_frame_commit(decor.frame, state, nullptr);
libdecor_state_free(state);
}
do_frame_resize = false;
force_frame_update = true;
}
else
#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
{
is_fractional_prev = is_fractional_next;
scale_prev = scale_next;
fractional_scale_prev = fractional_scale_next;
/* Leave `window_->frame_pending` as-is, so changes are detected and updates are applied. */
force_frame_update = true;
}
}
if ((fractional_scale_prev != fractional_scale_next) ||
@@ -2411,18 +2455,20 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
* NOTE: some flickering is still possible even when resizing this
* happens when dragging the right hand side of the title-bar in KDE
* as expanding changed the size on the RHS, this may be up to the compositor to fix. */
for (size_t i = 0; i < ARRAY_SIZE(window_->frame_pending.size); i++) {
const int value = window_->frame_pending.size[i] ? window_->frame_pending.size[i] :
window_->frame.size[i];
if (is_fractional_prev || is_fractional_next) {
window_->frame_pending.size[i] = lroundf(
value * (double(fractional_scale_next) / double(fractional_scale_prev)));
}
else {
window_->frame_pending.size[i] = (value * scale_next) / scale_prev;
}
if (window_->frame_pending.buffer_scale > 1) {
gwl_round_int_by(&window_->frame_pending.size[i], window_->frame_pending.buffer_scale);
if (do_frame_resize) {
for (size_t i = 0; i < ARRAY_SIZE(window_->frame_pending.size); i++) {
const int value = window_->frame_pending.size[i] ? window_->frame_pending.size[i] :
window_->frame.size[i];
if (is_fractional_prev || is_fractional_next) {
window_->frame_pending.size[i] = lroundf(
(value * (double(fractional_scale_next)) / double(fractional_scale_prev)));
}
else {
window_->frame_pending.size[i] = (value * scale_next) / scale_prev;
}
if (window_->frame_pending.buffer_scale > 1) {
gwl_round_int_by(&window_->frame_pending.size[i], window_->frame_pending.buffer_scale);
}
}
}