mirror of
https://github.com/telegramdesktop/tdesktop
synced 2024-12-24 15:34:20 +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:
parent
98cb85df66
commit
cf275b152a
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,7 @@ private:
|
||||
void updateLayerBoxes();
|
||||
void fixOrder();
|
||||
void sendFakeMouseEvent();
|
||||
void clearClosingLayers();
|
||||
|
||||
LayerWidget *currentLayer() {
|
||||
return _layers.empty() ? nullptr : _layers.back().get();
|
||||
@ -178,6 +179,7 @@ private:
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<LayerWidget>> _layers;
|
||||
std::vector<std::unique_ptr<LayerWidget>> _closingLayers;
|
||||
|
||||
object_ptr<LayerWidget> _specialLayer = { nullptr };
|
||||
object_ptr<MainMenu> _mainMenu = { nullptr };
|
||||
|
Loading…
Reference in New Issue
Block a user