2015-06-27 18:44:36 -07:00
|
|
|
/******************************************************************************
|
|
|
|
Copyright (C) 2015 by Hugh Bailey <obs.jim@gmail.com>
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include <QListWidget>
|
|
|
|
|
|
|
|
QListWidgetItem *TakeListItem(QListWidget *widget, int row)
|
|
|
|
{
|
|
|
|
QListWidgetItem *item = widget->item(row);
|
|
|
|
|
|
|
|
if (item)
|
|
|
|
delete widget->itemWidget(item);
|
|
|
|
|
|
|
|
return widget->takeItem(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeleteListItem(QListWidget *widget, QListWidgetItem *item)
|
|
|
|
{
|
|
|
|
if (item) {
|
|
|
|
delete widget->itemWidget(item);
|
|
|
|
delete item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClearListItems(QListWidget *widget)
|
|
|
|
{
|
UI: Clear ListItem selection before deleting widgets
This works around a crash in the "widget->clear()" call in
ClearListItems under the following circumstances:
- Create at least two scenes
- Create at least one source in both scenes
- Have at least one source selected in both scenes
- Set the same "Switch to scene" hotkey on both scenes
- Use "Switch to scene" hotkey
Reduced stack trace on my machine:
frame #0: 0x00000001004bac2d QtWidgets`QWidget::show() + 93
frame #1: 0x00000001006d32a2 QtWidgets`QAbstractItemView::updateEditorGeometries() + 690
frame #2: 0x00000001006d36d7 QtWidgets`QAbstractItemView::updateGeometries() + 23
frame #3: 0x00000001006f1ae6 QtWidgets`QListView::updateGeometries() + 438
frame #4: 0x00000001006ccdce QtWidgets`QAbstractItemView::doItemsLayout() + 46
frame #5: 0x00000001006f1916 QtWidgets`QListView::doItemsLayout() + 214
frame #6: 0x00000001006f9cf3 QtWidgets`QListViewPrivate::rectForIndex(QModelIndex const&) const + 611
frame #7: 0x00000001006eb48d QtWidgets`QListView::visualRect(QModelIndex const&) const + 29
frame #8: 0x00000001006f1567 QtWidgets`QListView::visualRegionForSelection(QItemSelection const&) const + 1863
frame #9: 0x00000001006d7ba9 QtWidgets`QAbstractItemView::selectionChanged(QItemSelection const&, QItemSelection const&) + 73
frame #10: 0x00000001006f97d2 QtWidgets`QListView::selectionChanged(QItemSelection const&, QItemSelection const&) + 674
frame #11: 0x00000001006d9b9e QtWidgets`QAbstractItemView::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 1246
frame #12: 0x0000000102b10372 QtCore`QMetaObject::activate(QObject*, int, int, void**) + 2994
frame #13: 0x0000000102aa001c QtCore`QItemSelectionModel::emitSelectionChanged(QItemSelection const&, QItemSelection const&) + 300
frame #14: 0x0000000102a9fe6c QtCore`QItemSelectionModel::select(QItemSelection const&, QFlags<QItemSelectionModel::SelectionFlag>) + 748
frame #15: 0x0000000102aa048b QtCore`QItemSelectionModel::clear() + 75
frame #16: 0x000000010072e9d8 QtWidgets`QListWidget::clear() + 24
frame #17: 0x000000010015759d obs`ClearListItems(widget=0x000000010683afa0) + 141 at item-widget-helpers.cpp:43
frame #18: 0x000000010003424b obs`OBSBasic::UpdateSources(this=0x0000000105f5bf50, scene=(val = obs_scene * = 0x0000000110679440)), &(obs_scene_release)>) + 75 at window-basic-main.cpp:1254
frame #19: 0x0000000100036a96 obs`OBSBasic::UpdateSceneSelection(this=0x0000000105f5bf50, source=<unavailable>), &(obs_source_release)>) + 422 at window-basic-main.cpp:1473
frame #20: 0x0000000100175c48 obs`OBSBasic::qt_static_metacall(_o=0x0000000105f5bf50, _c=InvokeMetaMethod, _id=17, _a=0x00007fff5fbfb640) + 776 at moc_window-basic-main.cpp:494
This crash was reported at
https://obsproject.com/mantis/view.php?id=364
2015-11-06 11:31:50 +01:00
|
|
|
widget->setCurrentItem(nullptr, QItemSelectionModel::Clear);
|
|
|
|
|
2015-06-27 18:44:36 -07:00
|
|
|
for (int i = 0; i < widget->count(); i++)
|
|
|
|
delete widget->itemWidget(widget->item(i));
|
|
|
|
|
UI: Do not delete via takeItem in ClearListItems
Apparently some raw lingering pointers to the item widgets may be
present inside of the QListView if you delete the item widgets directly,
and the only way to ensure those pointers are properly cleared is to
call ->clear() on the list widget instead of deleting each item
individually.
We were deleting each item individually because we thought that
->deleteLater might be also be called on other data within, but after
some testing, that turned out to not be the case, so it's safe to call
->clear() on the list widget.
As a note, deleting item widgets directly is dangerous due to the
potential for lingering raw internal pointers, and our case is unique
where we can get away with it; do not delete list item widgets directly
unless you intend on calling ->clear() or ->takeItem on the specific
item you do it to after.
Again, the reason why we are deleting list widget items manually is due
to the fact that Qt will always use ->deleteLater() on them if they are
not deleted manually, which puts their deletion on the queue. Only
problem is they cannot be removed from the queue once added, so
lingering references to sources will persist until the queue processes
them, which causes major problems if we need those objects deleted right
away.
2015-07-02 21:56:30 -07:00
|
|
|
widget->clear();
|
2015-06-27 18:44:36 -07:00
|
|
|
}
|