[ekiga] Turned the call history view code into a real GObject with signals
- From: Julien Puydt <jpuydt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ekiga] Turned the call history view code into a real GObject with signals
- Date: Thu, 7 Oct 2010 20:07:21 +0000 (UTC)
commit 50aef1514b0b4412684f36d1f0664bb130a2c82a
Author: Julien Puydt <jpuydt gnome org>
Date: Thu Oct 7 13:37:07 2010 +0200
Turned the call history view code into a real GObject with signals
This fixes bug #630792.
I thought I would only have to add the signals, but it wasn't even a
GObject! It did require some surgery in both the initialization and the
destruction code : we have to setup a GObject, and deal with disposing
(disconnecting signals for both boost and gtk+) in the right function.
It compiles and survives rapid tests, so it must not be that bad.
.../gui/gtk-frontend/call-history-view-gtk.cpp | 227 +++++++++++++++++---
.../gui/gtk-frontend/call-history-view-gtk.h | 49 +++++
2 files changed, 244 insertions(+), 32 deletions(-)
---
diff --git a/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp b/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
index db797db..3208ad1 100644
--- a/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
+++ b/lib/engine/gui/gtk-frontend/call-history-view-gtk.cpp
@@ -47,6 +47,19 @@
#include "gm-cell-renderer-bitext.h"
#include "gmstockicons.h"
+
+struct _CallHistoryViewGtkPrivate
+{
+ _CallHistoryViewGtkPrivate (boost::shared_ptr<History::Book> book_)
+ : book(book_)
+ {}
+
+ boost::shared_ptr<History::Book> book;
+ GtkTreeView* tree;
+ std::vector<boost::signals::connection> connections;
+};
+
+/* this is what we put in the view */
enum {
COLUMN_CONTACT,
COLUMN_PIXBUF,
@@ -55,17 +68,15 @@ enum {
COLUMN_NUMBER
};
+/* and this is the list of signals supported */
+enum {
+ CONTACT_SELECTED_SIGNAL,
+ LAST_SIGNAL
+};
-/* make sure we stop watching signals when the widget gets destroyed */
-static void
-destroy_connections (gpointer data,
- GObject */*unused*/)
-{
- std::list<boost::signals::connection> *conns
- = (std::list<boost::signals::connection> *)data;
+static guint signals[LAST_SIGNAL] = { 0 };
- delete conns;
-}
+static GObjectClass* parent_class = NULL;
/* react to a new call being inserted in history */
static void
@@ -192,29 +203,158 @@ on_clicked (GtkWidget *tree,
return TRUE;
}
+static void
+on_selection_changed (GtkTreeSelection* selection,
+ gpointer data)
+{
+ CallHistoryViewGtk* self = NULL;
+ GtkTreeModel* model = NULL;
+ GtkTreeIter iter;
+
+ self = CALL_HISTORY_VIEW_GTK (data);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+
+ History::Contact* contact = NULL;
+ gtk_tree_model_get (model, &iter,
+ COLUMN_CONTACT, &contact,
+ -1);
+ g_signal_emit (self, signals[CONTACT_SELECTED_SIGNAL], 0, contact);
+ } else
+ g_signal_emit (self, signals[CONTACT_SELECTED_SIGNAL], 0, NULL);
+}
+
+/* GObject stuff */
+static void
+call_history_view_gtk_dispose (GObject* obj)
+{
+ CallHistoryViewGtk* view = NULL;
+
+ view = CALL_HISTORY_VIEW_GTK (obj);
+
+ for (std::vector<boost::signals::connection>::iterator iter
+ = view->priv->connections.begin ();
+ iter != view->priv->connections.end ();
+ iter++)
+ iter->disconnect ();
+
+ if (view->priv->tree) {
+
+ GtkTreeSelection* selection = NULL;
+
+ selection = gtk_tree_view_get_selection (view->priv->tree);
+
+ g_signal_handlers_disconnect_matched (selection,
+ (GSignalMatchType) G_SIGNAL_MATCH_DATA,
+ 0, /* signal_id */
+ (GQuark) 0, /* detail */
+ NULL, /* closure */
+ NULL, /* func */
+ view /* data */);
+
+ g_signal_handlers_disconnect_matched (view->priv->tree,
+ (GSignalMatchType) G_SIGNAL_MATCH_DATA,
+ 0, /* signal_id */
+ (GQuark)0, /* detail */
+ NULL, /* closure */
+ NULL, /* func */
+ &(*(view->priv->book)) /* data */);
+ view->priv->tree = NULL;
+ }
+
+ parent_class->dispose (obj);
+}
+
+static void
+call_history_view_gtk_finalize (GObject* obj)
+{
+ CallHistoryViewGtk* view = NULL;
+
+ view = CALL_HISTORY_VIEW_GTK (obj);
+
+ delete view->priv;
+
+ parent_class->finalize (obj);
+}
+
+static void
+call_history_view_gtk_class_init (gpointer g_class,
+ gpointer /*class_data*/)
+{
+ CallHistoryViewGtkClass* call_history_view_gtk_class = NULL;
+ GObjectClass* gobject_class = NULL;
+
+ parent_class = (GObjectClass*) g_type_class_peek_parent (g_class);
+
+ gobject_class = (GObjectClass*)g_class;
+ gobject_class->dispose = call_history_view_gtk_dispose;
+ gobject_class->finalize = call_history_view_gtk_finalize;
+
+ signals[CONTACT_SELECTED_SIGNAL] =
+ g_signal_new ("contact-selected",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CallHistoryViewGtkClass, contact_selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ /* FIXME: is it useful? */
+ call_history_view_gtk_class = (CallHistoryViewGtkClass*)g_class;
+ call_history_view_gtk_class->contact_selected = NULL;
+}
+
+GType
+call_history_view_gtk_get_type ()
+{
+ static GType result = 0;
+
+ if (result == 0) {
+
+ static const GTypeInfo info = {
+ sizeof (CallHistoryViewGtkClass),
+ NULL,
+ NULL,
+ call_history_view_gtk_class_init,
+ NULL,
+ NULL,
+ sizeof (CallHistoryViewGtk),
+ 0,
+ NULL,
+ NULL
+ };
+
+ result = g_type_register_static (GTK_TYPE_SCROLLED_WINDOW,
+ "CallHistoryViewGtk",
+ &info, (GTypeFlags)0);
+ }
+
+ return result;
+}
+
/* public api */
GtkWidget *
call_history_view_gtk_new (boost::shared_ptr<History::Book> book)
{
- GtkWidget *result = NULL;
- std::list<boost::signals::connection> *conns = NULL;
+ CallHistoryViewGtk* self = NULL;
+
GtkListStore *store = NULL;
- GtkWidget *tree = NULL;
GtkTreeViewColumn *column = NULL;
GtkCellRenderer *renderer = NULL;
GtkTreeSelection *selection = NULL;
- boost::signals::connection connection;
- result = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (result),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ boost::signals::connection conn;
+
+ g_return_val_if_fail (book, (GtkWidget*)NULL);
- /* we don't leak conns : it will be freed when we die... and it will
- * prevent the signals to come to a now-dead GObject
- */
- conns = new std::list<boost::signals::connection>;
- g_object_weak_ref (G_OBJECT (result), destroy_connections, (gpointer)conns);
+ self = (CallHistoryViewGtk*)g_object_new (CALL_HISTORY_VIEW_GTK_TYPE, NULL);
+
+ self->priv = new _CallHistoryViewGtkPrivate (book);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
/* build the store then the tree */
store = gtk_list_store_new (COLUMN_NUMBER,
@@ -223,10 +363,10 @@ call_history_view_gtk_new (boost::shared_ptr<History::Book> book)
G_TYPE_STRING,
G_TYPE_STRING);
- tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ self->priv->tree = (GtkTreeView*)gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
g_object_unref (store);
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree), FALSE);
- gtk_container_add (GTK_CONTAINER (result), tree);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->tree), FALSE);
+ gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->tree));
/* one column should be enough for everyone */
column = gtk_tree_view_column_new ();
@@ -244,22 +384,45 @@ call_history_view_gtk_new (boost::shared_ptr<History::Book> book)
"primary-text", COLUMN_NAME);
gtk_tree_view_column_add_attribute (column, renderer,
"secondary-text", COLUMN_INFO);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+ gtk_tree_view_append_column (self->priv->tree, column);
/* react to user clicks */
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->tree));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
- g_signal_connect (G_OBJECT (tree), "event-after",
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (on_selection_changed), self);
+ g_signal_connect (G_OBJECT (self->priv->tree), "event-after",
G_CALLBACK (on_clicked), &(*book));
/* connect to the signals */
- connection = book->cleared.connect (boost::bind (>k_list_store_clear, store));
- conns->push_front (connection);
- connection = book->contact_added.connect (boost::bind (&on_contact_added, _1, store));
- conns->push_front (connection);
+ conn = book->cleared.connect (boost::bind (>k_list_store_clear, store));
+ self->priv->connections.push_back (conn);
+ conn = book->contact_added.connect (boost::bind (&on_contact_added, _1, store));
+ self->priv->connections.push_back (conn);
/* populate */
book->visit_contacts (boost::bind (&on_visit_contacts, _1, store));
- return result;
+ return (GtkWidget*)self;
+}
+
+void
+call_history_view_gtk_get_selected (CallHistoryViewGtk* self,
+ History::Contact** contact)
+{
+ g_return_if_fail (IS_CALL_HISTORY_VIEW_GTK (self) && contact != NULL);
+
+ GtkTreeSelection* selection = NULL;
+ GtkTreeModel* model = NULL;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (self->priv->tree);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_CONTACT, contact,
+ -1);
+ } else
+ *contact = NULL;
}
diff --git a/lib/engine/gui/gtk-frontend/call-history-view-gtk.h b/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
index 6b48ea0..ba949f6 100644
--- a/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
+++ b/lib/engine/gui/gtk-frontend/call-history-view-gtk.h
@@ -41,6 +41,55 @@
#include <gtk/gtk.h>
#include "history-book.h"
+typedef struct _CallHistoryViewGtk CallHistoryViewGtk;
+typedef struct _CallHistoryViewGtkPrivate CallHistoryViewGtkPrivate;
+typedef struct _CallHistoryViewGtkClass CallHistoryViewGtkClass;
+
+/*
+ * Public API
+ */
+
+/* creating the widget, connected to an History::Book object */
GtkWidget *call_history_view_gtk_new (boost::shared_ptr<History::Book> book);
+/* Knowing what is selected in the view */
+void call_history_view_gtk_get_selected (CallHistoryViewGtk* self,
+ History::Contact** contact);
+
+
+/* This widget emits a single signal :
+ * "contact-selected", comes with a pointer which is a History::Contact*
+ * (or NULL if no contact is selected anymore)
+ */
+
+/* GObject thingies */
+struct _CallHistoryViewGtk
+{
+ GtkScrolledWindow parent;
+
+ CallHistoryViewGtkPrivate* priv;
+};
+
+struct _CallHistoryViewGtkClass
+{
+ GtkScrolledWindowClass parent;
+
+ void (*contact_selected) (CallHistoryViewGtk* self,
+ gpointer contact);
+};
+
+#define CALL_HISTORY_VIEW_GTK_TYPE (call_history_view_gtk_get_type ())
+
+#define CALL_HISTORY_VIEW_GTK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALL_HISTORY_VIEW_GTK_TYPE, CallHistoryViewGtk))
+
+#define IS_CALL_HISTORY_VIEW_GTK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALL_HISTORY_VIEW_GTK_TYPE))
+
+#define CALL_HISTORY_VIEW_GTK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALL_HISTORY_VIEW_GTK_TYPE, CallHistoryViewGtkClass))
+
+#define IS_CALL_HISTORY_VIEW_GTK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALL_HISTORY_VIEW_GTK_TYPE))
+
+#define CALL_HISTORY_VIEW_GTK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALL_HISTORY_VIEW_GTK_TYPE, CallHistoryViewGtkClass))
+
+GType call_history_view_gtk_get_type ();
+
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]