Fix in-window preview (Wayland / noCompositing).

This commit is contained in:
John Preston 2023-01-06 20:00:58 +04:00
parent ff331c040a
commit 43a830f0af
2 changed files with 65 additions and 29 deletions

View file

@ -523,12 +523,11 @@ void SetupInterfaceScale(
if (values[i] <= scale if (values[i] <= scale
&& (i + 1 == valuesCount || values[i + 1] > scale)) { && (i + 1 == valuesCount || values[i + 1] > scale)) {
const auto x = (slider->width() * i) / (valuesCount - 1); const auto x = (slider->width() * i) / (valuesCount - 1);
const auto globalX = slider->mapToGlobal(QPoint(x, 0)).x(); togglePreview(show, scale, x);
togglePreview(show, scale, globalX);
return; return;
} }
} }
togglePreview(show, scale, QCursor::pos().x()); togglePreview(show, scale, slider->width() / 2);
}; };
const auto toggleHidePreview = [=] { const auto toggleHidePreview = [=] {
togglePreview(ScalePreviewShow::Hide, 0, 0); togglePreview(ScalePreviewShow::Hide, 0, 0);

View file

@ -38,18 +38,20 @@ constexpr auto kMaxTextLines = 3;
class Preview final { class Preview final {
public: public:
Preview(QWidget *parent, rpl::producer<QImage> userpic); Preview(QWidget *slider, rpl::producer<QImage> userpic);
void toggle(ScalePreviewShow show, int scale, int globalX); void toggle(ScalePreviewShow show, int scale, int globalX);
private: private:
void init(); void init();
void initAsWindow(); void initAsWindow();
void watchParent();
void reparent();
void updateToScale(int scale); void updateToScale(int scale);
void updateGlobalPosition(int globalX); void updateGlobalPosition(int globalX);
void updateGlobalPosition(); void updateGlobalPosition();
void updateWindowGlobalPosition(QPoint global, int globalX); void updateWindowGlobalPosition(QPoint global);
void updateOuterPosition(int globalX); void updateOuterPosition(int globalX);
[[nodiscard]] QRect adjustByScreenGeometry(QRect geometry) const; [[nodiscard]] QRect adjustByScreenGeometry(QRect geometry) const;
@ -86,6 +88,7 @@ private:
const QColor &color) const; const QColor &color) const;
Ui::RpWidget _widget; Ui::RpWidget _widget;
not_null<QWidget*> _slider;
Ui::ChatTheme _theme; Ui::ChatTheme _theme;
style::TextStyle _nameStyle = st::fwdTextStyle; style::TextStyle _nameStyle = st::fwdTextStyle;
Ui::Text::String _nameText = { kMaxTextWidth / 3 }; Ui::Text::String _nameText = { kMaxTextWidth / 3 };
@ -124,6 +127,7 @@ private:
bool _shown = false; bool _shown = false;
std::unique_ptr<QObject> _filter; std::unique_ptr<QObject> _filter;
std::unique_ptr<QObject> _parentWatcher;
}; };
@ -132,8 +136,9 @@ private:
&& Ui::Platform::TranslucentWindowsSupported(); && Ui::Platform::TranslucentWindowsSupported();
} }
Preview::Preview(QWidget *parent, rpl::producer<QImage> userpic) Preview::Preview(QWidget *slider, rpl::producer<QImage> userpic)
: _widget(parent) : _widget(slider->window())
, _slider(slider)
, _ratio(style::DevicePixelRatio()) , _ratio(style::DevicePixelRatio())
, _window(UseSeparateWindow()) { , _window(UseSeparateWindow()) {
std::move(userpic) | rpl::start_with_next([=](QImage &&userpic) { std::move(userpic) | rpl::start_with_next([=](QImage &&userpic) {
@ -144,10 +149,34 @@ Preview::Preview(QWidget *parent, rpl::producer<QImage> userpic)
} }
}, _widget.lifetime()); }, _widget.lifetime());
watchParent();
init(); 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<QEvent*> 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) { if (show == ScalePreviewShow::Hide) {
toggleShown(false); toggleShown(false);
return; return;
@ -155,7 +184,7 @@ void Preview::toggle(ScalePreviewShow show, int scale, int globalX) {
return; return;
} }
updateToScale(scale); updateToScale(scale);
updateGlobalPosition(globalX); updateGlobalPosition(sliderX);
if (_widget.isHidden()) { if (_widget.isHidden()) {
Ui::Platform::UpdateOverlayed(&_widget); Ui::Platform::UpdateOverlayed(&_widget);
} }
@ -215,7 +244,7 @@ void Preview::toggleFilter() {
} }
self(widget->parentWidget(), self); self(widget->parentWidget(), self);
}; };
watch(_widget.parentWidget(), watch); watch(_slider, watch);
const auto checkDeactivation = [=](Qt::ApplicationState state) { const auto checkDeactivation = [=](Qt::ApplicationState state) {
if (state != Qt::ApplicationActive) { if (state != Qt::ApplicationActive) {
@ -431,31 +460,41 @@ void Preview::updateToScale(int scale) {
_canvasCornerMasks = Images::CornersMask(scaled(6)); // st::callRadius _canvasCornerMasks = Images::CornersMask(scaled(6)); // st::callRadius
} }
void Preview::updateGlobalPosition(int globalX) { void Preview::updateGlobalPosition(int sliderX) {
const auto parent = _widget.parentWidget(); _localShiftLeft = sliderX;
if (_window) { if (_window) {
const auto global = parent->mapToGlobal(QPoint()); updateWindowGlobalPosition(_slider->mapToGlobal(QPoint()));
_localShiftLeft = globalX - global.x();
updateWindowGlobalPosition(global, globalX);
} else { } else {
const auto position = parent->pos(); updateGlobalPosition();
+ QPoint(parent->width() / 2, 0)
- QPoint(_outer.width() / 2, _outer.height());
_widget.setGeometry(QRect(position, _outer.size()));
updateOuterPosition(globalX);
} }
} }
void Preview::updateGlobalPosition() { void Preview::updateGlobalPosition() {
const auto parent = _widget.parentWidget(); if (_window) {
const auto global = parent->mapToGlobal(QPoint()); const auto global = _slider->mapToGlobal(QPoint());
updateWindowGlobalPosition(global, global.x() + _localShiftLeft); 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 desiredLeft = global.x() - (_minOuterSize.width() / 2);
const auto desiredRight = global.x() const auto desiredRight = global.x()
+ _widget.parentWidget()->width() + _slider->width()
+ (_maxOuterSize.width() / 2); + (_maxOuterSize.width() / 2);
const auto requiredLeft = desiredRight - _maxOuterSize.width(); const auto requiredLeft = desiredRight - _maxOuterSize.width();
const auto left = std::min(desiredLeft, requiredLeft); 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(); const auto top = global.y() - _maxOuterSize.height();
auto result = QRect(left, top, right - left, _maxOuterSize.height()); auto result = QRect(left, top, right - left, _maxOuterSize.height());
_widget.setGeometry(adjustByScreenGeometry(result)); _widget.setGeometry(adjustByScreenGeometry(result));
updateOuterPosition(globalX); updateOuterPosition(global.x() + _localShiftLeft);
} }
QRect Preview::adjustByScreenGeometry(QRect geometry) const { QRect Preview::adjustByScreenGeometry(QRect geometry) const {
const auto parent = _widget.parentWidget(); const auto screen = _slider->screen();
const auto screen = parent->screen();
if (!screen) { if (!screen) {
return geometry; return geometry;
} }
@ -716,7 +754,6 @@ void Preview::initAsWindow() {
[[nodiscard]] Fn<void(ScalePreviewShow, int, int)> SetupScalePreview( [[nodiscard]] Fn<void(ScalePreviewShow, int, int)> SetupScalePreview(
not_null<Window::Controller*> window, not_null<Window::Controller*> window,
not_null<Ui::RpWidget*> slider) { not_null<Ui::RpWidget*> slider) {
const auto parent = slider->parentWidget();
const auto controller = window->sessionController(); const auto controller = window->sessionController();
const auto user = controller const auto user = controller
? controller->session().user().get() ? controller->session().user().get()