mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-09-04 00:15:42 +00:00
Fix crash in layers closing.
Sometimes AbstractBox::setClosing invoked Ui::hideLayers that destroyed LayerStackWidget and all its children, including the closing AbstractBox. After that a unique_ptr stored on stack and owning that box was destroyed and it lead to a crash. Now LayerStackWidget always owns several closing boxes.
This commit is contained in:
@@ -618,15 +618,16 @@ void LayerStackWidget::replaceBox(
|
||||
object_ptr<BoxContent> box,
|
||||
anim::type animated) {
|
||||
const auto pointer = pushBox(std::move(box), animated);
|
||||
while (!_layers.empty() && _layers.front().get() != pointer) {
|
||||
auto removingLayer = std::move(_layers.front());
|
||||
_layers.erase(begin(_layers));
|
||||
|
||||
if (removingLayer->inFocusChain()) {
|
||||
setFocus();
|
||||
}
|
||||
removingLayer->setClosing();
|
||||
}
|
||||
const auto removeTill = ranges::find(
|
||||
_layers,
|
||||
pointer,
|
||||
&std::unique_ptr<LayerWidget>::get);
|
||||
_closingLayers.insert(
|
||||
end(_closingLayers),
|
||||
std::make_move_iterator(begin(_layers)),
|
||||
std::make_move_iterator(removeTill));
|
||||
_layers.erase(begin(_layers), removeTill);
|
||||
clearClosingLayers();
|
||||
}
|
||||
|
||||
void LayerStackWidget::prepareForAnimation() {
|
||||
@@ -780,12 +781,35 @@ bool LayerStackWidget::takeToThirdSection() {
|
||||
}
|
||||
|
||||
void LayerStackWidget::clearLayers() {
|
||||
for (auto list = base::take(_layers); !list.empty(); list.pop_back()) {
|
||||
const auto layer = std::move(list.back());
|
||||
_closingLayers.insert(
|
||||
end(_closingLayers),
|
||||
std::make_move_iterator(begin(_layers)),
|
||||
std::make_move_iterator(end(_layers)));
|
||||
_layers.clear();
|
||||
clearClosingLayers();
|
||||
}
|
||||
|
||||
void LayerStackWidget::clearClosingLayers() {
|
||||
const auto weak = make_weak(this);
|
||||
while (!_closingLayers.empty()) {
|
||||
const auto index = _closingLayers.size() - 1;
|
||||
const auto layer = _closingLayers.back().get();
|
||||
if (layer->inFocusChain()) {
|
||||
setFocus();
|
||||
}
|
||||
|
||||
// This may destroy LayerStackWidget (by calling Ui::hideLayer).
|
||||
// So each time we check a weak pointer (if we are still alive).
|
||||
layer->setClosing();
|
||||
if (weak) {
|
||||
// We could enqueue more closing layers, so we remove by index.
|
||||
Assert(index < _closingLayers.size());
|
||||
Assert(_closingLayers[index].get() == layer);
|
||||
_closingLayers.erase(begin(_closingLayers) + index);
|
||||
} else {
|
||||
// All layers were already destroyed in ~LayerStackWidget.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user