diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | liszt/Makefile.am | 32 | ||||
-rw-r--r-- | liszt/contact-view.c | 499 | ||||
-rw-r--r-- | liszt/contact-view.h | 44 | ||||
-rw-r--r-- | liszt/factory.c | 85 | ||||
-rw-r--r-- | liszt/factory.h | 42 | ||||
-rw-r--r-- | liszt/main.c | 131 |
8 files changed, 837 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 4d4462d2e..7d5015083 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -MY_SUBDIRS = tools extensions po data libempathy libempathy-gtk src help tests +MY_SUBDIRS = tools extensions po data libempathy libempathy-gtk src help tests liszt NST_SUBDIRS = nautilus-sendto-plugin DIST_SUBDIRS = $(MY_SUBDIRS) $(NST_SUBDIRS) diff --git a/configure.ac b/configure.ac index 00087c6ca..36332f371 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,8 @@ PKG_CHECK_MODULES(EMPATHY, libcanberra-gtk3 >= $LIBCANBERRA_GTK_REQUIRED libnotify >= $LIBNOTIFY_REQUIRED gcr-3 >= $KEYRING_REQUIRED + + mx-1.0 ]) # ----------------------------------------------------------- @@ -519,6 +521,7 @@ AC_OUTPUT([ tests/interactive/Makefile tests/xml/Makefile tools/Makefile + liszt/Makefile ]) echo " diff --git a/liszt/Makefile.am b/liszt/Makefile.am new file mode 100644 index 000000000..081e533d0 --- /dev/null +++ b/liszt/Makefile.am @@ -0,0 +1,32 @@ +include $(top_srcdir)/tools/flymake.mk + +CPPFLAGS_COMMON = \ + $(EMPATHY_CFLAGS) \ + $(ERROR_CFLAGS) \ + -I$(top_srcdir) \ + -DG_LOG_DOMAIN=\"liszt\" \ + $(DISABLE_DEPRECATED) \ + $(WARN_CFLAGS) \ + $(NULL) + +AM_CPPFLAGS = \ + $(CPPFLAGS_COMMON) \ + $(NULL) + +LDADD = \ + $(top_builddir)/libempathy-gtk/libempathy-gtk.la \ + $(top_builddir)/libempathy/libempathy.la \ + $(EMPATHY_LIBS) + +bin_PROGRAMS = \ + liszt \ + $(NULL) + +BUILT_SOURCES= + +liszt_SOURCES = \ + main.c factory.c factory. contact-view.c contact-view.h \ + $(NULL) + +CLEANFILES = $(BUILT_SOURCES) + diff --git a/liszt/contact-view.c b/liszt/contact-view.c new file mode 100644 index 000000000..41ef7978e --- /dev/null +++ b/liszt/contact-view.c @@ -0,0 +1,499 @@ +#include <folks/folks.h> +#include <folks/folks-telepathy.h> + +#include "contact-view.h" + +#include <libempathy/empathy-dispatcher.h> +#include <libempathy/empathy-call-factory.h> + +G_DEFINE_TYPE (LolContactView, lol_contact_view, CLUTTER_TYPE_BOX) + +/* signals */ +enum { + SELECTED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +/* properties */ +enum +{ + PROP_INDIVIDUAL = 1, +}; + +struct _LolContactViewPrivate +{ + FolksIndividual *individual; + + ClutterActor *presence_texture; + ClutterActor *name_text; + ClutterActor *avatar_texture; + ClutterActor *actions; + + gboolean selected; +}; + +static void +lol_contact_view_init (LolContactView *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, LOL_TYPE_CONTACT_VIEW, + LolContactViewPrivate); +} + +static const gchar * +lol_contact_view_get_presence_string (FolksPresenceType presence) +{ + switch (presence) + { + case FOLKS_PRESENCE_TYPE_AVAILABLE: + return "Available"; + break; + case FOLKS_PRESENCE_TYPE_AWAY: + case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY: + return "Away"; + break; + case FOLKS_PRESENCE_TYPE_HIDDEN: + case FOLKS_PRESENCE_TYPE_BUSY: + return "Busy"; + break; + case FOLKS_PRESENCE_TYPE_UNKNOWN: + case FOLKS_PRESENCE_TYPE_UNSET: + case FOLKS_PRESENCE_TYPE_OFFLINE: + case FOLKS_PRESENCE_TYPE_ERROR: + default: + return ""; + } +} + +static void +lol_contact_view_set_markup (LolContactView *self, + const gchar *text, + FolksPresenceType presence) +{ + LolContactViewPrivate *priv = self->priv; + gchar *markup; + + markup = g_strdup_printf ("%s\n<span size=\"x-small\">%s</span>", + text, lol_contact_view_get_presence_string (presence)); + clutter_text_set_markup (CLUTTER_TEXT (priv->name_text), markup); + g_free (markup); +} + +static void +lol_contact_view_set_avatar (LolContactView *self, + GFile *file) +{ + LolContactViewPrivate *priv = self->priv; + gchar *tmp; + + if (file == NULL) + return; + + tmp = g_file_get_path (file); + + clutter_texture_set_from_file ( + CLUTTER_TEXTURE (priv->avatar_texture), + tmp, NULL); + + g_free (tmp); +} + +static void +lol_contact_view_set_presence (LolContactView *self, + FolksPresenceType presence) +{ + LolContactViewPrivate *priv = self->priv; + const gchar *icon_name = NULL; + + switch (presence) + { + case FOLKS_PRESENCE_TYPE_AVAILABLE: + icon_name = "/usr/share/empathy/icons/hicolor/32x32/status/user-available.png"; + break; + case FOLKS_PRESENCE_TYPE_AWAY: + case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY: + icon_name = "/usr/share/empathy/icons/hicolor/32x32/status/user-away.png"; + break; + case FOLKS_PRESENCE_TYPE_HIDDEN: + case FOLKS_PRESENCE_TYPE_BUSY: + icon_name = "/usr/share/empathy/icons/hicolor/32x32/status/user-busy.png"; + break; + case FOLKS_PRESENCE_TYPE_UNKNOWN: + case FOLKS_PRESENCE_TYPE_UNSET: + case FOLKS_PRESENCE_TYPE_OFFLINE: + case FOLKS_PRESENCE_TYPE_ERROR: + break; + } + + if (icon_name == NULL) + return; + + clutter_texture_set_from_file ( + CLUTTER_TEXTURE (priv->presence_texture), + icon_name, NULL); +} + +static void +lol_contact_view_update_individual (LolContactView *self) +{ + + FolksIndividual *individual = self->priv->individual; + FolksPresenceType presence_type; + + presence_type = folks_presence_get_presence_type (FOLKS_PRESENCE (individual)); + + lol_contact_view_set_markup (self, + folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)), + presence_type); + + lol_contact_view_set_presence (self, presence_type); + + lol_contact_view_set_avatar (self, + folks_avatar_get_avatar (FOLKS_AVATAR (individual))); + + /* online */ + if (presence_type > FOLKS_PRESENCE_TYPE_OFFLINE + && presence_type < FOLKS_PRESENCE_TYPE_UNKNOWN) + { + clutter_actor_show (CLUTTER_ACTOR (self)); + } + else + { + clutter_actor_hide (CLUTTER_ACTOR (self)); + } +} + +static void +individual_notify_cb (FolksIndividual *individual, + GParamSpec *pspec, + LolContactView *self) +{ + lol_contact_view_update_individual (self); +} + +static void +lol_contact_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + LolContactView *self = (LolContactView *) object; + LolContactViewPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_INDIVIDUAL: + { + if (priv->individual == NULL) + { + priv->individual = g_value_dup_object (value); + lol_contact_view_update_individual (self); + g_signal_connect (priv->individual, "notify", + G_CALLBACK (individual_notify_cb), self); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +lol_contact_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + LolContactView *self = (LolContactView *) object; + LolContactViewPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_INDIVIDUAL: + g_value_set_object (value, priv->individual); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static TpContact * +get_contact_and_account (LolContactView *self, + TpAccount **account) +{ + LolContactViewPrivate *priv = self->priv; + GList *personas, *l; + FolksPersona *persona; + FolksPersonaStore *store; + TpContact *contact; + + personas = folks_individual_get_personas (priv->individual); + + for (l = personas; l != NULL; l = l->next) + { + if (!TPF_IS_PERSONA (l->data)) + continue; + + persona = l->data; + break; + } + + if (persona == NULL) + return NULL; + + store = folks_persona_get_store (persona); + contact = tpf_persona_get_contact (TPF_PERSONA (persona)); + + if (account != NULL) + *account = tpf_persona_store_get_account (TPF_PERSONA_STORE (store)); + + return contact; +} + +static void +chat_clicked_cb (MxButton *button, + LolContactView *self) +{ + TpContact *contact; + TpAccount *account; + + contact = get_contact_and_account (self, &account); + + if (contact == NULL) + return; + + empathy_dispatcher_chat_with_contact_id ( + account, + tp_contact_get_identifier (contact), + TP_USER_ACTION_TIME_CURRENT_TIME); +} + +static void +audio_call_clicked_cb (MxButton *button, + LolContactView *self) +{ + TpContact *contact; + TpAccount *account; + EmpathyContact *e_contact; + + contact = get_contact_and_account (self, &account); + + if (contact == NULL) + return; + + e_contact = empathy_contact_dup_from_tp_contact (contact); + + empathy_call_factory_new_call_with_streams (e_contact, + TRUE, FALSE, TP_USER_ACTION_TIME_CURRENT_TIME, + NULL); + + g_object_unref (e_contact); +} + +static void +video_call_clicked_cb (MxButton *button, + LolContactView *self) +{ + TpContact *contact; + TpAccount *account; + EmpathyContact *e_contact; + + contact = get_contact_and_account (self, &account); + + if (contact == NULL) + return; + + e_contact = empathy_contact_dup_from_tp_contact (contact); + + empathy_call_factory_new_call_with_streams (e_contact, + TRUE, TRUE, TP_USER_ACTION_TIME_CURRENT_TIME, + NULL); + + g_object_unref (e_contact); +} + +static void +lol_contact_view_constructed (GObject *obj) +{ + LolContactView *self = LOL_CONTACT_VIEW (obj); + LolContactViewPrivate *priv = self->priv; + ClutterBoxLayout *layout; + + ClutterActor *box, *button; + + void (*chain_up) (GObject *) = + ((GObjectClass *) lol_contact_view_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (obj); + + layout = CLUTTER_BOX_LAYOUT (clutter_box_get_layout_manager (CLUTTER_BOX (self))); + clutter_box_layout_set_spacing (layout, 10); + clutter_box_layout_set_vertical (layout, TRUE); + + box = clutter_box_new (clutter_box_layout_new ()); + clutter_actor_set_height (box, 48.0); + + priv->presence_texture = clutter_texture_new (); + clutter_actor_set_height (priv->presence_texture, 32.0); + clutter_actor_set_width (priv->presence_texture, 32.0); + clutter_box_pack (CLUTTER_BOX (box), priv->presence_texture, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_actor_show (priv->presence_texture); + + priv->name_text = clutter_text_new (); + clutter_box_pack (CLUTTER_BOX (box), priv->name_text, + "x-align", CLUTTER_BOX_ALIGNMENT_START, + "y-align", CLUTTER_BOX_ALIGNMENT_CENTER, + "x-fill", TRUE, + "y-fill", FALSE, + "expand", TRUE, + NULL); + clutter_actor_show (priv->name_text); + + priv->avatar_texture = clutter_texture_new (); + clutter_actor_set_height (priv->avatar_texture, 32.0); + clutter_actor_set_width (priv->avatar_texture, 32.0); + clutter_box_pack (CLUTTER_BOX (box), priv->avatar_texture, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_actor_show (priv->avatar_texture); + + /* add the first hbox to the vbox */ + clutter_box_pack (CLUTTER_BOX (obj), box, + "expand", TRUE, + "x-fill", TRUE, + "y-fill", TRUE, + NULL); + + /* now onto the second box */ + layout = CLUTTER_BOX_LAYOUT (clutter_box_layout_new ()); + priv->actions = clutter_box_new (CLUTTER_LAYOUT_MANAGER (layout)); + clutter_actor_set_height (priv->actions, 32.0); + + button = mx_button_new_with_label ("Chat"); + clutter_box_pack (CLUTTER_BOX (priv->actions), button, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_box_layout_set_alignment (layout, button, + CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_START); + + g_signal_connect (button, "clicked", G_CALLBACK (chat_clicked_cb), self); + + button = mx_button_new_with_label ("Audio Call"); + clutter_box_pack (CLUTTER_BOX (priv->actions), button, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_box_layout_set_alignment (layout, button, + CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_START); + + g_signal_connect (button, "clicked", G_CALLBACK (audio_call_clicked_cb), self); + + button = mx_button_new_with_label ("Video Call"); + clutter_box_pack (CLUTTER_BOX (priv->actions), button, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_box_layout_set_alignment (layout, button, + CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_START); + + g_signal_connect (button, "clicked", G_CALLBACK (video_call_clicked_cb), self); + + clutter_box_pack (CLUTTER_BOX (obj), priv->actions, + "expand", TRUE, + "x-fill", TRUE, + "y-fill", TRUE, + NULL); + clutter_actor_hide (priv->actions); + + clutter_actor_hide (CLUTTER_ACTOR (self)); +} + +static void +lol_contact_view_dispose (GObject *obj) +{ + LolContactView *self = LOL_CONTACT_VIEW (obj); + + if (self->priv->individual != NULL) + { + g_object_unref (self->priv->individual); + self->priv->individual = NULL; + } + + if (G_OBJECT_CLASS (lol_contact_view_parent_class)->finalize != NULL) + G_OBJECT_CLASS (lol_contact_view_parent_class)->finalize (obj); +} + +static void +lol_contact_view_class_init (LolContactViewClass *cls) +{ + GObjectClass *object_class = G_OBJECT_CLASS (cls); + + object_class->set_property = lol_contact_view_set_property; + object_class->get_property = lol_contact_view_get_property; + object_class->constructed = lol_contact_view_constructed; + object_class->dispose = lol_contact_view_dispose; + + g_object_class_install_property (object_class, + PROP_INDIVIDUAL, + g_param_spec_object ("individual", "Individual", "FolksIndividual", + FOLKS_TYPE_INDIVIDUAL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + signals[SELECTED] = g_signal_new ("selected", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + g_type_class_add_private (cls, sizeof (LolContactViewPrivate)); +} + +LolContactView * +lol_contact_view_new (void) +{ + return g_object_new (LOL_TYPE_CONTACT_VIEW, + "layout-manager", clutter_box_layout_new (), + "reactive", TRUE, + NULL); +} + +void +lol_contact_view_toggle_selected (LolContactView *self) +{ + LolContactViewPrivate *priv = self->priv; + ClutterColor blue = { 83, 136, 224, 255 }; + ClutterColor white = { 255, 255, 255, 255 }; + ClutterColor black = { 0, 0, 0, 255 }; + + priv->selected = !priv->selected; + + if (priv->selected) + { + clutter_box_set_color (CLUTTER_BOX (self), &blue); + clutter_actor_show (priv->actions); + clutter_text_set_color (CLUTTER_TEXT (priv->name_text), &white); + } + else + { + clutter_box_set_color (CLUTTER_BOX (self), &white); + clutter_actor_hide (priv->actions); + clutter_text_set_color (CLUTTER_TEXT (priv->name_text), &black); + } + + g_signal_emit (self, signals[SELECTED], 0, priv->selected); +} diff --git a/liszt/contact-view.h b/liszt/contact-view.h new file mode 100644 index 000000000..46015d3ed --- /dev/null +++ b/liszt/contact-view.h @@ -0,0 +1,44 @@ +#ifndef __LOL_CONTACT_VIEW_H__ +#define __LOL_CONTACT_VIEW_H__ + +#include <mx/mx.h> + +typedef struct _LolContactView LolContactView; +typedef struct _LolContactViewClass LolContactViewClass; +typedef struct _LolContactViewPrivate LolContactViewPrivate; + +GType lol_contact_view_get_type (void); + +#define LOL_TYPE_CONTACT_VIEW \ + (lol_contact_view_get_type ()) +#define LOL_CONTACT_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOL_TYPE_CONTACT_VIEW, \ + LolContactView)) +#define LOL_CONTACT_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOL_TYPE_CONTACT_VIEW, \ + LolContactViewClass)) +#define LOL_IS_CONTACT_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOL_TYPE_CONTACT_VIEW)) +#define LOL_IS_CONTACT_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOL_TYPE_CONTACT_VIEW)) +#define LOL_CONTACT_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOL_TYPE_CONTACT_VIEW, \ + LolContactViewClass)) + +struct _LolContactView +{ + ClutterBox parent; + LolContactViewPrivate *priv; +}; + +struct _LolContactViewClass +{ + ClutterBoxClass parent_class; + gpointer priv; +}; + +LolContactView * lol_contact_view_new (void); + +void lol_contact_view_toggle_selected (LolContactView *self); + +#endif diff --git a/liszt/factory.c b/liszt/factory.c new file mode 100644 index 000000000..9b17f6201 --- /dev/null +++ b/liszt/factory.c @@ -0,0 +1,85 @@ +#include "factory.h" +#include "contact-view.h" + +static void item_factory_init (gpointer g_iface, gpointer data); + +G_DEFINE_TYPE_WITH_CODE (LolFactory, lol_factory, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MX_TYPE_ITEM_FACTORY, item_factory_init)) + +struct _LolFactoryPrivate +{ + LolContactView *selected; +}; + +static void +lol_factory_init (LolFactory *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, LOL_TYPE_FACTORY, + LolFactoryPrivate); +} + +static void +lol_factory_class_init (LolFactoryClass *cls) +{ + g_type_class_add_private (cls, sizeof (LolFactoryPrivate)); +} + +LolFactory * +lol_factory_new (void) +{ + return g_object_new (LOL_TYPE_FACTORY, + NULL); +} + +static void +selected_cb (LolContactView *view, + gboolean status, + LolFactory *self) +{ + LolFactoryPrivate *priv = self->priv; + + /* current selected contact has been de-selected */ + if (priv->selected == view && !status) + { + priv->selected = NULL; + return; + } + + /* unselect the curently selected contact */ + if (priv->selected != NULL) + lol_contact_view_toggle_selected (LOL_CONTACT_VIEW (priv->selected)); + + priv->selected = view; +} + +static gboolean +button_press_event_cb (ClutterActor *actor, + ClutterEvent *event, + LolFactory *self) +{ + lol_contact_view_toggle_selected (LOL_CONTACT_VIEW (actor)); + + return TRUE; +} + +static ClutterActor * +create (MxItemFactory *factory) +{ + ClutterActor *out = CLUTTER_ACTOR (lol_contact_view_new ()); + + g_signal_connect (out, "button-press-event", + G_CALLBACK (button_press_event_cb), factory); + g_signal_connect (out, "selected", + G_CALLBACK (selected_cb), factory); + + return out; +} + +static void +item_factory_init (gpointer g_iface, + gpointer data G_GNUC_UNUSED) +{ + MxItemFactoryIface *iface = g_iface; + + iface->create = create; +} diff --git a/liszt/factory.h b/liszt/factory.h new file mode 100644 index 000000000..8dd4eca85 --- /dev/null +++ b/liszt/factory.h @@ -0,0 +1,42 @@ +#ifndef __LOL_FACTORY_H__ +#define __LOL_FACTORY_H__ + +#include <mx/mx.h> + +typedef struct _LolFactory LolFactory; +typedef struct _LolFactoryClass LolFactoryClass; +typedef struct _LolFactoryPrivate LolFactoryPrivate; + +GType lol_factory_get_type (void); + +#define LOL_TYPE_FACTORY \ + (lol_factory_get_type ()) +#define LOL_FACTORY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOL_TYPE_FACTORY, \ + LolFactory)) +#define LOL_FACTORY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOL_TYPE_FACTORY, \ + LolFactoryClass)) +#define LOL_IS_FACTORY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOL_TYPE_FACTORY)) +#define LOL_IS_FACTORY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOL_TYPE_FACTORY)) +#define LOL_FACTORY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOL_TYPE_FACTORY, \ + LolFactoryClass)) + +struct _LolFactory +{ + GObject parent; + LolFactoryPrivate *priv; +}; + +struct _LolFactoryClass +{ + GObjectClass parent_class; + gpointer priv; +}; + +LolFactory *lol_factory_new (void); + +#endif diff --git a/liszt/main.c b/liszt/main.c new file mode 100644 index 000000000..00f5092c3 --- /dev/null +++ b/liszt/main.c @@ -0,0 +1,131 @@ +#include <mx/mx.h> +#include <folks/folks.h> + +#include "factory.h" + +enum +{ + COLUMN_INDIVIDUAL, + N_COLUMNS +}; + +static void +aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator, + GList *added, + GList *removed, + const char *message, + FolksPersona *actor, + guint reason, + ClutterModel *model) +{ + GList *l; + + for (l = added; l != NULL; l = l->next) + { + FolksIndividual *individual = l->data; + + if (folks_individual_get_is_user (individual)) + continue; + + clutter_model_append (model, + COLUMN_INDIVIDUAL, individual, + -1); + } +} + +/* breaks avatars for now +static gint +model_sort_func (ClutterModel *model, + const GValue *a, + const GValue *b, + gpointer user_data) +{ + FolksIndividual *one = g_value_get_object (a); + FolksIndividual *two = g_value_get_object (b); + gint ret; + + ret = folks_presence_typecmp ( + folks_presence_get_presence_type (FOLKS_PRESENCE (one)), + folks_presence_get_presence_type (FOLKS_PRESENCE (two))); + + if (ret != 0) + return ret; + + return strcmp (folks_aliasable_get_alias (FOLKS_ALIASABLE (one)), + folks_aliasable_get_alias (FOLKS_ALIASABLE (two))); +} +*/ + +static ClutterModel * +create_model (FolksIndividualAggregator *aggregator) +{ + ClutterModel *model; + + model = clutter_list_model_new (N_COLUMNS, + FOLKS_TYPE_INDIVIDUAL, "individual"); + + /* + clutter_model_set_sort (model, COLUMN_INDIVIDUAL, model_sort_func, + NULL, NULL); + */ + + folks_individual_aggregator_prepare (aggregator, NULL, NULL); + + g_signal_connect (aggregator, "individuals-changed", + G_CALLBACK (aggregator_individuals_changed_cb), model); + + return model; +} + +int +main (int argc, char **argv) +{ + MxApplication *application; + FolksIndividualAggregator *aggregator; + MxWindow *window; + ClutterActor *stage, *toolbar, *layout, *combo, *scroll, *view; + + application = mx_application_new (&argc, &argv, "Contact list", + MX_APPLICATION_SINGLE_INSTANCE); + + aggregator = folks_individual_aggregator_new (); + + window = mx_application_create_window (application); + stage = (ClutterActor *) mx_window_get_clutter_stage (window); + + /* toolbar */ + toolbar = (ClutterActor *) mx_window_get_toolbar (window); + mx_bin_set_fill (MX_BIN (toolbar), TRUE, FALSE); + + layout = mx_box_layout_new (); + + combo = mx_combo_box_new (); + clutter_container_add_actor (CLUTTER_CONTAINER (layout), combo); + mx_combo_box_append_text (MX_COMBO_BOX (combo), "All Contacts"); + mx_combo_box_append_text (MX_COMBO_BOX (combo), "Work"); + mx_combo_box_append_text (MX_COMBO_BOX (combo), "Play"); + mx_combo_box_append_text (MX_COMBO_BOX (combo), "Girls"); + mx_combo_box_set_index (MX_COMBO_BOX (combo), 0); + + clutter_container_add_actor (CLUTTER_CONTAINER (toolbar), layout); + + /* main stage */ + scroll = mx_scroll_view_new (); + mx_window_set_child (window, scroll); + + view = mx_list_view_new (); + mx_list_view_add_attribute (MX_LIST_VIEW (view), "individual", COLUMN_INDIVIDUAL); + + mx_list_view_set_factory (MX_LIST_VIEW (view), MX_ITEM_FACTORY (lol_factory_new ())); + mx_list_view_set_model (MX_LIST_VIEW (view), create_model (aggregator)); + + clutter_container_add_actor (CLUTTER_CONTAINER (scroll), view); + + clutter_actor_show (stage); + + mx_application_run (application); + + g_object_unref (aggregator); + + return 0; +} |