fix a crash sometimes happening on close

the problem is that sometimes when QCoreApplication::aboutToQuit the containment is already deleted (the order is not really deterministic), therefore appletScript::applet() will hit an assert.
using a qpointer should solve it, its data being already 0ed in the cases the containment is already deleted at :aboutToquit time.
This commit is contained in:
Marco Martin 2014-07-08 11:04:05 +02:00
parent 2f93b7f764
commit a5ecb2e0ff
2 changed files with 60 additions and 63 deletions

View File

@ -57,46 +57,39 @@ ContainmentInterface::ContainmentInterface(DeclarativeAppletScript *parent, cons
m_wallpaperInterface(0),
m_activityInfo(0)
{
m_containment = static_cast<Plasma::Containment *>(appletScript()->applet()->containment());
setAcceptedMouseButtons(Qt::AllButtons);
connect(containment(), &Plasma::Containment::appletRemoved,
connect(m_containment.data(), &Plasma::Containment::appletRemoved,
this, &ContainmentInterface::appletRemovedForward);
connect(containment(), &Plasma::Containment::appletAdded,
connect(m_containment.data(), &Plasma::Containment::appletAdded,
this, &ContainmentInterface::appletAddedForward);
connect(containment(), &Plasma::Containment::activityChanged,
connect(m_containment.data(), &Plasma::Containment::activityChanged,
this, &ContainmentInterface::activityChanged);
connect(containment(), &Plasma::Containment::activityChanged,
connect(m_containment.data(), &Plasma::Containment::activityChanged,
[ = ]() {
delete m_activityInfo;
m_activityInfo = new KActivities::Info(containment()->activity(), this);
m_activityInfo = new KActivities::Info(m_containment->activity(), this);
connect(m_activityInfo, &KActivities::Info::nameChanged,
this, &ContainmentInterface::activityNameChanged);
emit activityNameChanged();
});
connect(containment(), &Plasma::Containment::wallpaperChanged,
connect(m_containment.data(), &Plasma::Containment::wallpaperChanged,
this, &ContainmentInterface::loadWallpaper);
connect(containment(), &Plasma::Containment::containmentTypeChanged,
connect(m_containment.data(), &Plasma::Containment::containmentTypeChanged,
this, &ContainmentInterface::containmentTypeChanged);
if (containment()->corona()) {
connect(containment()->corona(), &Plasma::Corona::availableScreenRegionChanged,
if (m_containment->corona()) {
connect(m_containment->corona(), &Plasma::Corona::availableScreenRegionChanged,
this, &ContainmentInterface::availableScreenRegionChanged);
connect(containment()->corona(), &Plasma::Corona::availableScreenRectChanged,
connect(m_containment->corona(), &Plasma::Corona::availableScreenRectChanged,
this, &ContainmentInterface::availableScreenRectChanged);
}
if (!m_appletInterfaces.isEmpty()) {
emit appletsChanged();
}
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
[=]() {
if (!containment()) {
return;
}
disconnect(containment(), &Plasma::Containment::appletRemoved,
this, &ContainmentInterface::appletRemovedForward);
});
}
void ContainmentInterface::init()
@ -105,7 +98,7 @@ void ContainmentInterface::init()
return;
}
m_activityInfo = new KActivities::Info(containment()->activity(), this);
m_activityInfo = new KActivities::Info(m_containment->activity(), this);
connect(m_activityInfo, &KActivities::Info::nameChanged,
this, &ContainmentInterface::activityNameChanged);
emit activityNameChanged();
@ -113,13 +106,12 @@ void ContainmentInterface::init()
AppletInterface::init();
//Create the ToolBox
Plasma::Containment *pc = containment();
if (pc) {
if (m_containment) {
KConfigGroup defaults;
if (pc->containmentType() == Plasma::Types::DesktopContainment) {
defaults = KConfigGroup(KSharedConfig::openConfig(pc->corona()->package().filePath("defaults")), "Desktop");
} else if (pc->containmentType() == Plasma::Types::PanelContainment) {
defaults = KConfigGroup(KSharedConfig::openConfig(pc->corona()->package().filePath("defaults")), "Panel");
if (m_containment->containmentType() == Plasma::Types::DesktopContainment) {
defaults = KConfigGroup(KSharedConfig::openConfig(m_containment->corona()->package().filePath("defaults")), "Desktop");
} else if (m_containment->containmentType() == Plasma::Types::PanelContainment) {
defaults = KConfigGroup(KSharedConfig::openConfig(m_containment->corona()->package().filePath("defaults")), "Panel");
}
Plasma::Package pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic");
@ -160,7 +152,7 @@ void ContainmentInterface::init()
prop.write(expr.evaluate());
}
if (!containment()->wallpaper().isEmpty()) {
if (!m_containment->wallpaper().isEmpty()) {
loadWallpaper();
}
}
@ -184,14 +176,14 @@ QVariantList ContainmentInterface::availableScreenRegion() const
{
QRegion reg = QRect(0, 0, width(), height());
int screenId = screen();
if (screenId > -1 && containment()->corona()) {
reg = containment()->corona()->availableScreenRegion(screenId);
if (screenId > -1 && m_containment->corona()) {
reg = m_containment->corona()->availableScreenRegion(screenId);
}
QVariantList regVal;
foreach (QRect rect, reg.rects()) {
//make it relative
QRect geometry = containment()->corona()->screenGeometry(screenId);
QRect geometry = m_containment->corona()->screenGeometry(screenId);
rect.moveTo(rect.topLeft() - geometry.topLeft());
regVal << QVariant::fromValue(QRectF(rect));
}
@ -204,10 +196,10 @@ QRect ContainmentInterface::availableScreenRect() const
int screenId = screen();
if (screenId > -1 && containment()->corona()) {
rect = containment()->corona()->availableScreenRect(screenId);
if (screenId > -1 && m_containment->corona()) {
rect = m_containment->corona()->availableScreenRect(screenId);
//make it relative
QRect geometry = containment()->corona()->screenGeometry(screenId);
QRect geometry = m_containment->corona()->screenGeometry(screenId);
rect.moveTo(rect.topLeft() - geometry.topLeft());
}
@ -219,7 +211,7 @@ Plasma::Applet *ContainmentInterface::createApplet(const QString &plugin, const
//HACK
//This is necessary to delay the appletAdded signal (of containmentInterface) AFTER the applet graphics object has been created
blockSignals(true);
Plasma::Applet *applet = containment()->createApplet(plugin, args);
Plasma::Applet *applet = m_containment->createApplet(plugin, args);
if (applet) {
QObject *appletGraphicObject = applet->property("_plasma_graphicObject").value<QObject *>();
@ -248,7 +240,7 @@ void ContainmentInterface::setAppletArgs(Plasma::Applet *applet, const QString &
QObject *ContainmentInterface::containmentAt(int x, int y)
{
foreach (Plasma::Containment *c, containment()->corona()->containments()) {
foreach (Plasma::Containment *c, m_containment->corona()->containments()) {
ContainmentInterface *contInterface = c->property("_plasma_graphicObject").value<ContainmentInterface *>();
if (contInterface && contInterface->isVisible()) {
@ -263,12 +255,12 @@ QObject *ContainmentInterface::containmentAt(int x, int y)
void ContainmentInterface::addApplet(AppletInterface *applet, int x, int y)
{
if (!applet || applet->applet()->containment() == containment()) {
if (!applet || applet->applet()->containment() == m_containment) {
return;
}
blockSignals(true);
containment()->addApplet(applet->applet());
m_containment->addApplet(applet->applet());
blockSignals(false);
emit appletAdded(applet, x, y);
}
@ -559,9 +551,9 @@ void ContainmentInterface::appletAddedForward(Plasma::Applet *applet)
}
QObject *appletGraphicObject = applet->property("_plasma_graphicObject").value<QObject *>();
QObject *contGraphicObject = containment()->property("_plasma_graphicObject").value<QObject *>();
QObject *contGraphicObject = m_containment->property("_plasma_graphicObject").value<QObject *>();
// qDebug() << "Applet added on containment:" << containment()->title() << contGraphicObject
// qDebug() << "Applet added on containment:" << m_containment->title() << contGraphicObject
// << "Applet: " << applet << applet->title() << appletGraphicObject;
if (!appletGraphicObject) {
@ -582,6 +574,10 @@ void ContainmentInterface::appletAddedForward(Plasma::Applet *applet)
void ContainmentInterface::appletRemovedForward(Plasma::Applet *applet)
{
if (QCoreApplication::closingDown()) {
return;
}
QObject *appletGraphicObject = applet->property("_plasma_graphicObject").value<QObject *>();
m_appletInterfaces.removeAll(appletGraphicObject);
emit appletRemoved(appletGraphicObject);
@ -590,12 +586,12 @@ void ContainmentInterface::appletRemovedForward(Plasma::Applet *applet)
void ContainmentInterface::loadWallpaper()
{
if (containment()->containmentType() != Plasma::Types::DesktopContainment &&
containment()->containmentType() != Plasma::Types::CustomContainment) {
if (m_containment->containmentType() != Plasma::Types::DesktopContainment &&
m_containment->containmentType() != Plasma::Types::CustomContainment) {
return;
}
if (!containment()->wallpaper().isEmpty()) {
if (!m_containment->wallpaper().isEmpty()) {
delete m_wallpaperInterface;
m_wallpaperInterface = new WallpaperInterface(this);
@ -608,7 +604,7 @@ void ContainmentInterface::loadWallpaper()
QQmlProperty prop(m_wallpaperInterface, "anchors.fill");
prop.write(expr.evaluate());
containment()->setProperty("wallpaperGraphicsObject", QVariant::fromValue(m_wallpaperInterface));
m_containment->setProperty("wallpaperGraphicsObject", QVariant::fromValue(m_wallpaperInterface));
} else {
if (m_wallpaperInterface) {
m_wallpaperInterface->deleteLater();
@ -619,7 +615,7 @@ void ContainmentInterface::loadWallpaper()
QString ContainmentInterface::activity() const
{
return containment()->activity();
return m_containment->activity();
}
QString ContainmentInterface::activityName() const
@ -636,10 +632,10 @@ QList<QObject *> ContainmentInterface::actions() const
//use a multimap to sort by action type
QMultiMap<int, QObject *> actions;
foreach (QAction *a, containment()->actions()->actions()) {
foreach (QAction *a, m_containment->actions()->actions()) {
actions.insert(a->data().toInt(), a);
}
foreach (QAction *a, containment()->corona()->actions()->actions()) {
foreach (QAction *a, m_containment->corona()->actions()->actions()) {
if (a->objectName() == QStringLiteral("lock widgets")) {
//It is up to the Containment to decide if the user is allowed or not
//to lock/unluck the widgets, so corona should not add one when there is none
@ -656,7 +652,7 @@ QList<QObject *> ContainmentInterface::actions() const
void ContainmentInterface::mousePressEvent(QMouseEvent *event)
{
event->setAccepted(containment()->containmentActions().contains(Plasma::ContainmentActions::eventToString(event)));
event->setAccepted(m_containment->containmentActions().contains(Plasma::ContainmentActions::eventToString(event)));
}
void ContainmentInterface::mouseReleaseEvent(QMouseEvent *event)
@ -669,7 +665,7 @@ void ContainmentInterface::mouseReleaseEvent(QMouseEvent *event)
}
const QString trigger = Plasma::ContainmentActions::eventToString(event);
Plasma::ContainmentActions *plugin = containment()->containmentActions().value(trigger);
Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
if (!plugin || plugin->contextualActions().isEmpty()) {
event->setAccepted(false);
@ -723,7 +719,7 @@ void ContainmentInterface::mouseReleaseEvent(QMouseEvent *event)
void ContainmentInterface::wheelEvent(QWheelEvent *event)
{
const QString trigger = Plasma::ContainmentActions::eventToString(event);
Plasma::ContainmentActions *plugin = containment()->containmentActions().value(trigger);
Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
if (plugin) {
if (event->delta() < 0) {
@ -756,7 +752,7 @@ void ContainmentInterface::addAppletActions(QMenu &desktopMenu, Plasma::Applet *
}
}
QMenu *containmentMenu = new QMenu(i18nc("%1 is the name of the containment", "%1 Options", containment()->title()), &desktopMenu);
QMenu *containmentMenu = new QMenu(i18nc("%1 is the name of the containment", "%1 Options", m_containment->title()), &desktopMenu);
addContainmentActions(*containmentMenu, event);
if (!containmentMenu->isEmpty()) {
@ -784,8 +780,8 @@ void ContainmentInterface::addAppletActions(QMenu &desktopMenu, Plasma::Applet *
}
}
if (containment()->immutability() == Plasma::Types::Mutable &&
(containment()->containmentType() != Plasma::Types::PanelContainment || containment()->isUserConfiguring())) {
if (m_containment->immutability() == Plasma::Types::Mutable &&
(m_containment->containmentType() != Plasma::Types::PanelContainment || m_containment->isUserConfiguring())) {
QAction *closeApplet = applet->actions()->action("remove");
//qDebug() << "checking for removal" << closeApplet;
if (closeApplet) {
@ -801,7 +797,7 @@ void ContainmentInterface::addAppletActions(QMenu &desktopMenu, Plasma::Applet *
void ContainmentInterface::addContainmentActions(QMenu &desktopMenu, QEvent *event)
{
if (containment()->corona()->immutability() != Plasma::Types::Mutable &&
if (m_containment->corona()->immutability() != Plasma::Types::Mutable &&
!KAuthorized::authorizeKAction("plasma/containment_actions")) {
//qDebug() << "immutability";
return;
@ -809,18 +805,18 @@ void ContainmentInterface::addContainmentActions(QMenu &desktopMenu, QEvent *eve
//this is what ContainmentPrivate::prepareContainmentActions was
const QString trigger = Plasma::ContainmentActions::eventToString(event);
Plasma::ContainmentActions *plugin = containment()->containmentActions().value(trigger);
Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
if (!plugin) {
return;
}
if (plugin->containment() != containment()) {
plugin->setContainment(containment());
if (plugin->containment() != m_containment) {
plugin->setContainment(m_containment);
// now configure it
KConfigGroup cfg(containment()->corona()->config(), "ActionPlugins");
cfg = KConfigGroup(&cfg, QString::number(containment()->containmentType()));
KConfigGroup cfg(m_containment->corona()->config(), "ActionPlugins");
cfg = KConfigGroup(&cfg, QString::number(m_containment->containmentType()));
KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
plugin->restore(pluginConfig);
}
@ -830,10 +826,10 @@ void ContainmentInterface::addContainmentActions(QMenu &desktopMenu, QEvent *eve
if (actions.isEmpty()) {
//it probably didn't bother implementing the function. give the user a chance to set
//a better plugin. note that if the user sets no-plugin this won't happen...
if ((containment()->containmentType() != Plasma::Types::PanelContainment &&
containment()->containmentType() != Plasma::Types::CustomPanelContainment) &&
containment()->actions()->action("configure")) {
desktopMenu.addAction(containment()->actions()->action("configure"));
if ((m_containment->containmentType() != Plasma::Types::PanelContainment &&
m_containment->containmentType() != Plasma::Types::CustomPanelContainment) &&
m_containment->actions()->action("configure")) {
desktopMenu.addAction(m_containment->actions()->action("configure"));
}
} else {
desktopMenu.addActions(actions);

View File

@ -87,7 +87,7 @@ public:
//Not for QML
Plasma::Containment *containment() const
{
return static_cast<Plasma::Containment *>(appletScript()->applet()->containment());
return m_containment.data();
}
inline WallpaperInterface *wallpaperInterface() const
@ -196,6 +196,7 @@ private:
QHash<KJob *, QPoint> m_dropPoints;
QHash<KJob *, QMenu *> m_dropMenus;
KActivities::Info *m_activityInfo;
QPointer<Plasma::Containment> m_containment;
QWeakPointer<QMenu> m_contextMenu;
};