main window: fix dataChanged inception
Because setData can be called inside of a Qt signal handler, a
dataChanged signal handler can then also be called as a result
(since connections made using lambdas are called directly, rather
than being scheduled on the main loop).
In this case it caused item_changed() to be called inside of
selection_changed() in certain cases resulting in 2 CurrentCallViews
to be constructed and one of them was never destroyed.
The fix is to place the handler on the main loop queue via a g_idle
call so that its not called inside of another handler.
Tuleap: #252
Change-Id: I4a091037075af3823fc74cfd80fd3ac5bd7b0926
diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp
index c7ef228..acb05ab 100644
--- a/src/ringmainwindow.cpp
+++ b/src/ringmainwindow.cpp
@@ -261,21 +261,18 @@
}
}
-static void
-item_changed(const QModelIndex& recent_idx, RingMainWindow *win)
+static gboolean
+selected_item_changed(RingMainWindow *win)
{
// g_debug("item changed");
RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
/* if we're showing the settings, then nothing needs to be done as the call
view is not shown */
- if (priv->show_settings) return;
+ if (priv->show_settings) return G_SOURCE_REMOVE;
- /* check if the item that changed is the same as the one selected / displayed */
auto idx_selected = RecentModel::instance().selectionModel()->currentIndex();
- if (idx_selected != recent_idx) return;
-
/* we prioritize showing the call view; but if the call is over we go back to showing the chat view */
if(auto call = RecentModel::instance().getActiveCall(idx_selected)) {
/* check if we need to change the view */
@@ -341,6 +338,8 @@
}
}
}
+
+ return G_SOURCE_REMOVE;
}
static void
@@ -951,7 +950,13 @@
&RecentModel::instance(),
&RecentModel::dataChanged,
[win](const QModelIndex & topLeft, G_GNUC_UNUSED const QModelIndex & bottomRight, G_GNUC_UNUSED const QVector<int> & roles) {
- item_changed(topLeft, win);
+ /* it is possible for dataChanged to be emitted inside of a dataChanged handler or
+ * some other signal; since the connection is via a lambda, Qt would cause the
+ * handler to be called directly. This is not behaviour we usually want, so we call our
+ * function via g_idle so that it gets called after the initial handler is done.
+ */
+ if (topLeft == RecentModel::instance().selectionModel()->currentIndex())
+ g_idle_add((GSourceFunc)selected_item_changed, win);
}
);