From 43a830f0afa41a0b97fd935f4be641d6be87fd95 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 6 Jan 2023 20:00:58 +0400 Subject: [PATCH] Fix in-window preview (Wayland / noCompositing). --- .../SourceFiles/settings/settings_main.cpp | 5 +- .../settings/settings_scale_preview.cpp | 89 +++++++++++++------ 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index e72ae77f1..c7a98d385 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -523,12 +523,11 @@ void SetupInterfaceScale( if (values[i] <= scale && (i + 1 == valuesCount || values[i + 1] > scale)) { const auto x = (slider->width() * i) / (valuesCount - 1); - const auto globalX = slider->mapToGlobal(QPoint(x, 0)).x(); - togglePreview(show, scale, globalX); + togglePreview(show, scale, x); return; } } - togglePreview(show, scale, QCursor::pos().x()); + togglePreview(show, scale, slider->width() / 2); }; const auto toggleHidePreview = [=] { togglePreview(ScalePreviewShow::Hide, 0, 0); diff --git a/Telegram/SourceFiles/settings/settings_scale_preview.cpp b/Telegram/SourceFiles/settings/settings_scale_preview.cpp index e92e32623..222f04224 100644 --- a/Telegram/SourceFiles/settings/settings_scale_preview.cpp +++ b/Telegram/SourceFiles/settings/settings_scale_preview.cpp @@ -38,18 +38,20 @@ constexpr auto kMaxTextLines = 3; class Preview final { public: - Preview(QWidget *parent, rpl::producer userpic); + Preview(QWidget *slider, rpl::producer userpic); void toggle(ScalePreviewShow show, int scale, int globalX); private: void init(); void initAsWindow(); + void watchParent(); + void reparent(); void updateToScale(int scale); void updateGlobalPosition(int globalX); void updateGlobalPosition(); - void updateWindowGlobalPosition(QPoint global, int globalX); + void updateWindowGlobalPosition(QPoint global); void updateOuterPosition(int globalX); [[nodiscard]] QRect adjustByScreenGeometry(QRect geometry) const; @@ -86,6 +88,7 @@ private: const QColor &color) const; Ui::RpWidget _widget; + not_null _slider; Ui::ChatTheme _theme; style::TextStyle _nameStyle = st::fwdTextStyle; Ui::Text::String _nameText = { kMaxTextWidth / 3 }; @@ -124,6 +127,7 @@ private: bool _shown = false; std::unique_ptr _filter; + std::unique_ptr _parentWatcher; }; @@ -132,8 +136,9 @@ private: && Ui::Platform::TranslucentWindowsSupported(); } -Preview::Preview(QWidget *parent, rpl::producer userpic) -: _widget(parent) +Preview::Preview(QWidget *slider, rpl::producer userpic) +: _widget(slider->window()) +, _slider(slider) , _ratio(style::DevicePixelRatio()) , _window(UseSeparateWindow()) { std::move(userpic) | rpl::start_with_next([=](QImage &&userpic) { @@ -144,10 +149,34 @@ Preview::Preview(QWidget *parent, rpl::producer userpic) } }, _widget.lifetime()); + watchParent(); + init(); } -void Preview::toggle(ScalePreviewShow show, int scale, int globalX) { +void Preview::watchParent() { + const auto parent = _widget.parentWidget(); + _parentWatcher.reset(base::install_event_filter(parent, [=]( + not_null e) { + if (e->type() == QEvent::ParentChange) { + if (_widget.window() != parent) { + reparent(); + } + } + return base::EventFilterResult::Continue; + })); +} + +void Preview::reparent() { + _widget.setParent(_widget.window()); + if (_shown) { + _widget.show(); + updateGlobalPosition(); + } + watchParent(); +} + +void Preview::toggle(ScalePreviewShow show, int scale, int sliderX) { if (show == ScalePreviewShow::Hide) { toggleShown(false); return; @@ -155,7 +184,7 @@ void Preview::toggle(ScalePreviewShow show, int scale, int globalX) { return; } updateToScale(scale); - updateGlobalPosition(globalX); + updateGlobalPosition(sliderX); if (_widget.isHidden()) { Ui::Platform::UpdateOverlayed(&_widget); } @@ -215,7 +244,7 @@ void Preview::toggleFilter() { } self(widget->parentWidget(), self); }; - watch(_widget.parentWidget(), watch); + watch(_slider, watch); const auto checkDeactivation = [=](Qt::ApplicationState state) { if (state != Qt::ApplicationActive) { @@ -431,31 +460,41 @@ void Preview::updateToScale(int scale) { _canvasCornerMasks = Images::CornersMask(scaled(6)); // st::callRadius } -void Preview::updateGlobalPosition(int globalX) { - const auto parent = _widget.parentWidget(); +void Preview::updateGlobalPosition(int sliderX) { + _localShiftLeft = sliderX; if (_window) { - const auto global = parent->mapToGlobal(QPoint()); - _localShiftLeft = globalX - global.x(); - updateWindowGlobalPosition(global, globalX); + updateWindowGlobalPosition(_slider->mapToGlobal(QPoint())); } else { - const auto position = parent->pos(); - + QPoint(parent->width() / 2, 0) - - QPoint(_outer.width() / 2, _outer.height()); - _widget.setGeometry(QRect(position, _outer.size())); - updateOuterPosition(globalX); + updateGlobalPosition(); } } void Preview::updateGlobalPosition() { - const auto parent = _widget.parentWidget(); - const auto global = parent->mapToGlobal(QPoint()); - updateWindowGlobalPosition(global, global.x() + _localShiftLeft); + if (_window) { + const auto global = _slider->mapToGlobal(QPoint()); + updateWindowGlobalPosition(global); + } else { + const auto parent = _widget.parentWidget(); + const auto global = Ui::MapFrom(parent, _slider, QPoint()); + const auto desiredLeft = global.x() + + _localShiftLeft + - (_outer.width() / 2); + const auto desiredTop = global.y() - _outer.height(); + const auto requiredRight = std::min( + desiredLeft + _outer.width(), + parent->width()); + const auto left = std::max( + std::min(desiredLeft, requiredRight - _outer.width()), + 0); + _widget.setGeometry(QRect(QPoint(left, desiredTop), _outer.size())); + } + _widget.raise(); } -void Preview::updateWindowGlobalPosition(QPoint global, int globalX) { +void Preview::updateWindowGlobalPosition(QPoint global) { const auto desiredLeft = global.x() - (_minOuterSize.width() / 2); const auto desiredRight = global.x() - + _widget.parentWidget()->width() + + _slider->width() + (_maxOuterSize.width() / 2); const auto requiredLeft = desiredRight - _maxOuterSize.width(); const auto left = std::min(desiredLeft, requiredLeft); @@ -464,12 +503,11 @@ void Preview::updateWindowGlobalPosition(QPoint global, int globalX) { const auto top = global.y() - _maxOuterSize.height(); auto result = QRect(left, top, right - left, _maxOuterSize.height()); _widget.setGeometry(adjustByScreenGeometry(result)); - updateOuterPosition(globalX); + updateOuterPosition(global.x() + _localShiftLeft); } QRect Preview::adjustByScreenGeometry(QRect geometry) const { - const auto parent = _widget.parentWidget(); - const auto screen = parent->screen(); + const auto screen = _slider->screen(); if (!screen) { return geometry; } @@ -716,7 +754,6 @@ void Preview::initAsWindow() { [[nodiscard]] Fn SetupScalePreview( not_null window, not_null slider) { - const auto parent = slider->parentWidget(); const auto controller = window->sessionController(); const auto user = controller ? controller->session().user().get()