From 71efd10c83c50620c00aa5ae238360b70b975e2b Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Tue, 4 Dec 2018 11:19:28 +0400
Subject: [PATCH] Fix crash on layer -> section migration.

---
 .../SourceFiles/info/info_layer_widget.cpp    | 41 +++++++++++++++----
 Telegram/SourceFiles/info/info_memento.cpp    |  2 +
 Telegram/SourceFiles/window/layer_widget.cpp  | 29 +++++++++----
 3 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/Telegram/SourceFiles/info/info_layer_widget.cpp b/Telegram/SourceFiles/info/info_layer_widget.cpp
index c5aea6f2b..52ffc11cd 100644
--- a/Telegram/SourceFiles/info/info_layer_widget.cpp
+++ b/Telegram/SourceFiles/info/info_layer_widget.cpp
@@ -56,12 +56,16 @@ not_null<Window::Controller*> LayerWidget::floatPlayerController() {
 
 not_null<Window::AbstractSectionWidget*> LayerWidget::floatPlayerGetSection(
 		Window::Column column) {
+	Expects(_content != nullptr);
+
 	return _content;
 }
 
 void LayerWidget::floatPlayerEnumerateSections(Fn<void(
 		not_null<Window::AbstractSectionWidget*> widget,
 		Window::Column widgetColumn)> callback) {
+	Expects(_content != nullptr);
+
 	callback(_content, Window::Column::Second);
 }
 
@@ -70,6 +74,8 @@ bool LayerWidget::floatPlayerIsVisible(not_null<HistoryItem*> item) {
 }
 
 void LayerWidget::setupHeightConsumers() {
+	Expects(_content != nullptr);
+
 	_content->scrollTillBottomChanges(
 	) | rpl::filter([this] {
 		return !_inResize;
@@ -90,14 +96,33 @@ void LayerWidget::showFinished() {
 }
 
 void LayerWidget::parentResized() {
+	if (!_content) {
+		return;
+	}
+
 	auto parentSize = parentWidget()->size();
 	auto parentWidth = parentSize.width();
 	if (parentWidth < MinimalSupportedWidth()) {
 		Ui::FocusPersister persister(this);
-		auto localCopy = _controller;
+		restoreFloatPlayerDelegate();
+
 		auto memento = MoveMemento(std::move(_content));
-		localCopy->hideSpecialLayer(anim::type::instant);
-		localCopy->showSection(
+
+		// We want to call hideSpecialLayer synchronously to avoid glitches,
+		// but we can't destroy LayerStackWidget from its' resizeEvent,
+		// because QWidget has such code for resizing:
+		//
+		// QResizeEvent e(r.size(), olds);
+		// QApplication::sendEvent(q, &e);
+		// if (q->windowHandle())
+		//   q->update();
+		//
+		// So we call it queued. It would be cool to call it 'right after'
+		// the resize event handling was finished.
+		InvokeQueued(this, [=] {
+			_controller->hideSpecialLayer(anim::type::instant);
+		});
+		_controller->showSection(
 			std::move(memento),
 			Window::SectionShow(
 				Window::SectionShow::Way::Forward,
@@ -153,7 +178,7 @@ bool LayerWidget::takeToThirdSection() {
 bool LayerWidget::showSectionInternal(
 		not_null<Window::SectionMemento*> memento,
 		const Window::SectionShow &params) {
-	if (_content->showInternal(memento, params)) {
+	if (_content && _content->showInternal(memento, params)) {
 		if (params.activation != anim::activation::background) {
 			Ui::hideLayer();
 		}
@@ -163,11 +188,11 @@ bool LayerWidget::showSectionInternal(
 }
 
 bool LayerWidget::closeByOutsideClick() const {
-	return _content->closeByOutsideClick();
+	return _content ? _content->closeByOutsideClick() : true;
 }
 
 int LayerWidget::MinimalSupportedWidth() {
-	auto minimalMargins = 2 * st::infoMinimalLayerMargin;
+	const auto minimalMargins = 2 * st::infoMinimalLayerMargin;
 	return st::infoMinimalWidth + minimalMargins;
 }
 
@@ -225,7 +250,9 @@ int LayerWidget::resizeGetHeight(int newWidth) {
 }
 
 void LayerWidget::doSetInnerFocus() {
-	_content->setInnerFocus();
+	if (_content) {
+		_content->setInnerFocus();
+	}
 }
 
 void LayerWidget::paintEvent(QPaintEvent *e) {
diff --git a/Telegram/SourceFiles/info/info_memento.cpp b/Telegram/SourceFiles/info/info_memento.cpp
index 2427fb447..e94a18e8b 100644
--- a/Telegram/SourceFiles/info/info_memento.cpp
+++ b/Telegram/SourceFiles/info/info_memento.cpp
@@ -164,6 +164,8 @@ Memento::~Memento() = default;
 
 MoveMemento::MoveMemento(object_ptr<WrapWidget> content)
 : _content(std::move(content)) {
+	_content->hide();
+	_content->setParent(nullptr);
 }
 
 object_ptr<Window::SectionWidget> MoveMemento::createWidget(
diff --git a/Telegram/SourceFiles/window/layer_widget.cpp b/Telegram/SourceFiles/window/layer_widget.cpp
index 43a5add9a..73e9fa726 100644
--- a/Telegram/SourceFiles/window/layer_widget.cpp
+++ b/Telegram/SourceFiles/window/layer_widget.cpp
@@ -497,16 +497,16 @@ void LayerStackWidget::closeLayer(not_null<LayerWidget*> layer) {
 }
 
 void LayerStackWidget::updateLayerBoxes() {
-	auto getLayerBox = [this]() {
-		if (auto layer = currentLayer()) {
+	const auto layerBox = [&] {
+		if (const auto layer = currentLayer()) {
 			return layer->geometry();
 		}
 		return QRect();
-	};
-	auto getSpecialLayerBox = [this]() {
-		return _specialLayer ? _specialLayer->geometry() : QRect();
-	};
-	_background->setLayerBoxes(getSpecialLayerBox(), getLayerBox());
+	}();
+	const auto specialLayerBox = _specialLayer
+		? _specialLayer->geometry()
+		: QRect();
+	_background->setLayerBoxes(specialLayerBox, layerBox);
 	update();
 }
 
@@ -566,15 +566,28 @@ void LayerStackWidget::startAnimation(
 }
 
 void LayerStackWidget::resizeEvent(QResizeEvent *e) {
+	const auto weak = make_weak(this);
 	_background->setGeometry(rect());
+	if (!weak) {
+		return;
+	}
 	if (_specialLayer) {
 		_specialLayer->parentResized();
+		if (!weak) {
+			return;
+		}
 	}
-	if (auto layer = currentLayer()) {
+	if (const auto layer = currentLayer()) {
 		layer->parentResized();
+		if (!weak) {
+			return;
+		}
 	}
 	if (_mainMenu) {
 		_mainMenu->resize(_mainMenu->width(), height());
+		if (!weak) {
+			return;
+		}
 	}
 	updateLayerBoxes();
 }