[empathy] Adium: Let user select theme variant in preferences



commit b708db960de0882d0e0db9610f5b5ad490581a65
Author: Xavier Claessens <xclaesse gmail com>
Date:   Tue May 3 11:27:21 2011 +0200

    Adium: Let user select theme variant in preferences
    
    Fixes bug #585474

 data/org.gnome.Empathy.gschema.xml.in  |    5 +
 libempathy-gtk/empathy-theme-adium.c   |  134 +++++++++++-----
 libempathy-gtk/empathy-theme-adium.h   |    5 +-
 libempathy-gtk/empathy-theme-manager.c |  284 +++++++++++++++++++-------------
 libempathy/empathy-gsettings.h         |    1 +
 src/empathy-preferences.c              |  175 +++++++++++++++++++-
 src/empathy-preferences.ui             |   63 ++++----
 7 files changed, 482 insertions(+), 185 deletions(-)
---
diff --git a/data/org.gnome.Empathy.gschema.xml.in b/data/org.gnome.Empathy.gschema.xml.in
index 799cc72..50b3005 100644
--- a/data/org.gnome.Empathy.gschema.xml.in
+++ b/data/org.gnome.Empathy.gschema.xml.in
@@ -183,6 +183,11 @@ present them to the user immediately.</_description>
       <_summary>Chat window theme</_summary>
       <_description>The theme that is used to display the conversation in chat windows.</_description>
     </key>
+    <key name="theme-variant" type="s">
+      <default>''</default>
+      <_summary>Chat window theme variant</_summary>
+      <_description>The theme variant that is used to display the conversation in chat windows.</_description>
+    </key>
     <key name="adium-path" type="s">
       <default>''</default>
       <_summary>Path of the Adium theme to use</_summary>
diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c
index b0bd09a..0370b90 100644
--- a/libempathy-gtk/empathy-theme-adium.c
+++ b/libempathy-gtk/empathy-theme-adium.c
@@ -69,6 +69,8 @@ typedef struct {
 	gboolean              has_focus;
 	gboolean              has_unread_message;
 	gboolean              allow_scrolling;
+	gchar                *variant;
+	gboolean              in_construction;
 } EmpathyThemeAdiumPriv;
 
 struct _EmpathyAdiumData {
@@ -104,10 +106,12 @@ struct _EmpathyAdiumData {
 };
 
 static void theme_adium_iface_init (EmpathyChatViewIface *iface);
+static gchar * adium_info_dup_path_for_variant (GHashTable *info, const gchar *variant);
 
 enum {
 	PROP_0,
 	PROP_ADIUM_DATA,
+	PROP_VARIANT,
 };
 
 G_DEFINE_TYPE_WITH_CODE (EmpathyThemeAdium, empathy_theme_adium,
@@ -230,6 +234,27 @@ string_with_format (const gchar *format,
 }
 
 static void
+theme_adium_load_template (EmpathyThemeAdium *theme)
+{
+	EmpathyThemeAdiumPriv *priv = GET_PRIV (theme);
+	gchar                 *basedir_uri;
+	gchar                 *variant_path;
+	gchar                 *template;
+
+	priv->pages_loading++;
+	basedir_uri = g_strconcat ("file://", priv->data->basedir, NULL);
+	variant_path = adium_info_dup_path_for_variant (priv->data->info,
+		priv->variant);
+	template = string_with_format (priv->data->template_html,
+		variant_path, NULL);
+	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (theme),
+					  template, basedir_uri);
+	g_free (basedir_uri);
+	g_free (variant_path);
+	g_free (template);
+}
+
+static void
 theme_adium_match_newline (const gchar *text,
 			   gssize len,
 			   EmpathyStringReplace replace_func,
@@ -1018,14 +1043,8 @@ static void
 theme_adium_clear (EmpathyChatView *view)
 {
 	EmpathyThemeAdiumPriv *priv = GET_PRIV (view);
-	gchar *basedir_uri;
 
-	priv->pages_loading++;
-	basedir_uri = g_strconcat ("file://", priv->data->basedir, NULL);
-	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (view),
-					  priv->data->template_html,
-					  basedir_uri);
-	g_free (basedir_uri);
+	theme_adium_load_template (EMPATHY_THEME_ADIUM (view));
 
 	/* Clear last contact to avoid trying to add a 'joined'
 	 * message when we don't have an insertion point. */
@@ -1503,7 +1522,6 @@ static void
 theme_adium_constructed (GObject *object)
 {
 	EmpathyThemeAdiumPriv *priv = GET_PRIV (object);
-	gchar                 *basedir_uri;
 	const gchar           *font_family = NULL;
 	gint                   font_size = 0;
 	WebKitWebView         *webkit_view = WEBKIT_WEB_VIEW (object);
@@ -1534,13 +1552,9 @@ theme_adium_constructed (GObject *object)
 			  object);
 
 	/* Load template */
-	priv->pages_loading = 1;
+	theme_adium_load_template (EMPATHY_THEME_ADIUM (object));
 
-	basedir_uri = g_strconcat ("file://", priv->data->basedir, NULL);
-	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (object),
-					  priv->data->template_html,
-					  basedir_uri);
-	g_free (basedir_uri);
+	priv->in_construction = FALSE;
 }
 
 static void
@@ -1555,6 +1569,9 @@ theme_adium_get_property (GObject    *object,
 	case PROP_ADIUM_DATA:
 		g_value_set_boxed (value, priv->data);
 		break;
+	case PROP_VARIANT:
+		g_value_set_string (value, priv->variant);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 		break;
@@ -1567,6 +1584,7 @@ theme_adium_set_property (GObject      *object,
 			  const GValue *value,
 			  GParamSpec   *pspec)
 {
+	EmpathyThemeAdium *theme = EMPATHY_THEME_ADIUM (object);
 	EmpathyThemeAdiumPriv *priv = GET_PRIV (object);
 
 	switch (param_id) {
@@ -1574,6 +1592,9 @@ theme_adium_set_property (GObject      *object,
 		g_assert (priv->data == NULL);
 		priv->data = g_value_dup_boxed (value);
 		break;
+	case PROP_VARIANT:
+		empathy_theme_adium_set_variant (theme, g_value_get_string (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 		break;
@@ -1603,6 +1624,15 @@ empathy_theme_adium_class_init (EmpathyThemeAdiumClass *klass)
 							      G_PARAM_CONSTRUCT_ONLY |
 							      G_PARAM_READWRITE |
 							      G_PARAM_STATIC_STRINGS));
+	g_object_class_install_property (object_class,
+					 PROP_VARIANT,
+					 g_param_spec_string ("variant",
+							      "The theme variant",
+							      "Variant name for the theme",
+							      NULL,
+							      G_PARAM_CONSTRUCT |
+							      G_PARAM_READWRITE |
+							      G_PARAM_STATIC_STRINGS));
 
 	g_type_class_add_private (object_class, sizeof (EmpathyThemeAdiumPriv));
 }
@@ -1615,6 +1645,7 @@ empathy_theme_adium_init (EmpathyThemeAdium *theme)
 
 	theme->priv = priv;
 
+	priv->in_construction = TRUE;
 	g_queue_init (&priv->message_queue);
 	priv->allow_scrolling = TRUE;
 	priv->smiley_manager = empathy_smiley_manager_dup_singleton ();
@@ -1636,15 +1667,49 @@ empathy_theme_adium_init (EmpathyThemeAdium *theme)
 }
 
 EmpathyThemeAdium *
-empathy_theme_adium_new (EmpathyAdiumData *data)
+empathy_theme_adium_new (EmpathyAdiumData *data,
+			 const gchar *variant)
 {
 	g_return_val_if_fail (data != NULL, NULL);
 
 	return g_object_new (EMPATHY_TYPE_THEME_ADIUM,
 			     "adium-data", data,
+			     "variant", variant,
 			     NULL);
 }
 
+void
+empathy_theme_adium_set_variant (EmpathyThemeAdium *theme,
+				 const gchar *variant)
+{
+	EmpathyThemeAdiumPriv *priv = GET_PRIV (theme);
+	gchar *variant_path;
+	gchar *script;
+
+	if (!tp_strdiff (priv->variant, variant)) {
+		return;
+	}
+
+	g_free (priv->variant);
+	priv->variant = g_strdup (variant);
+
+	if (priv->in_construction) {
+		return;
+	}
+
+	DEBUG ("Update view with variant: '%s'", variant);
+	variant_path = adium_info_dup_path_for_variant (priv->data->info,
+		priv->variant);
+	script = g_strdup_printf ("setStylesheet(\"mainStyle\",\"%s\");", variant_path);
+
+	webkit_web_view_execute_script (WEBKIT_WEB_VIEW (theme), script);
+
+	g_free (variant_path);
+	g_free (script);
+
+	g_object_notify (G_OBJECT (theme), "variant");
+}
+
 gboolean
 empathy_adium_path_is_valid (const gchar *path)
 {
@@ -1717,33 +1782,31 @@ adium_info_get_no_variant_name (GHashTable *info)
 	return name ? name : _("Normal");
 }
 
-static const gchar *
-adium_info_get_default_or_first_variant (GHashTable *info)
-{
-	const gchar *name;
-	GPtrArray *variants;
-
-	name = empathy_adium_info_get_default_variant (info);
-	if (name != NULL) {
-		return name;
-	}
-
-	variants = empathy_adium_info_get_available_variants (info);
-	g_assert (variants->len > 0);
-	return g_ptr_array_index (variants, 0);
-}
-
 static gchar *
 adium_info_dup_path_for_variant (GHashTable *info,
 				 const gchar *variant)
 {
 	guint version = adium_info_get_version (info);
 	const gchar *no_variant = adium_info_get_no_variant_name (info);
+	GPtrArray *variants;
+	guint i;
 
 	if (version <= 2 && !tp_strdiff (variant, no_variant)) {
 		return g_strdup ("main.css");
 	}
 
+	/* Verify the variant exists, fallback to the first one */
+	variants = empathy_adium_info_get_available_variants (info);
+	for (i = 0; i < variants->len; i++) {
+		if (!tp_strdiff (variant, g_ptr_array_index (variants, i))) {
+			break;
+		}
+	}
+	if (i == variants->len) {
+		DEBUG ("Variant %s does not exist", variant);
+		variant = g_ptr_array_index (variants, 0);
+	}
+
 	return g_strdup_printf ("Variants/%s.css", variant);
 
 }
@@ -1827,7 +1890,6 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info)
 	EmpathyAdiumData *data;
 	gchar            *template_html = NULL;
 	gchar            *footer_html = NULL;
-	gchar            *variant_path;
 	gchar            *tmp;
 
 	g_return_val_if_fail (empathy_adium_path_is_valid (path), NULL);
@@ -1928,15 +1990,12 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info)
 		g_free (tmp);
 	}
 
-	variant_path = adium_info_dup_path_for_variant (info,
-		adium_info_get_default_or_first_variant (info));
-
 	/* Old custom templates had only 4 parameters.
 	 * New templates have 5 parameters */
 	if (data->version <= 2 && data->custom_template) {
 		tmp = string_with_format (template_html,
 			data->basedir,
-			variant_path,
+			"%@", /* Leave variant unset */
 			"", /* The header */
 			footer_html ? footer_html : "",
 			NULL);
@@ -1944,7 +2003,7 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info)
 		tmp = string_with_format (template_html,
 			data->basedir,
 			data->version <= 2 ? "" : "@import url( \"main.css\" );",
-			variant_path,
+			"%@", /* Leave variant unset */
 			"", /* The header */
 			footer_html ? footer_html : "",
 			NULL);
@@ -1954,7 +2013,6 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info)
 
 	g_free (template_html);
 	g_free (footer_html);
-	g_free (variant_path);
 
 	return data;
 }
diff --git a/libempathy-gtk/empathy-theme-adium.h b/libempathy-gtk/empathy-theme-adium.h
index d0ad017..1c01b7b 100644
--- a/libempathy-gtk/empathy-theme-adium.h
+++ b/libempathy-gtk/empathy-theme-adium.h
@@ -49,7 +49,10 @@ struct _EmpathyThemeAdiumClass {
 };
 
 GType              empathy_theme_adium_get_type (void) G_GNUC_CONST;
-EmpathyThemeAdium *empathy_theme_adium_new      (EmpathyAdiumData *data);
+EmpathyThemeAdium *empathy_theme_adium_new      (EmpathyAdiumData *data,
+						 const gchar *variant);
+void               empathy_theme_adium_set_variant (EmpathyThemeAdium *theme,
+						    const gchar *variant);
 
 gboolean           empathy_adium_path_is_valid (const gchar *path);
 
diff --git a/libempathy-gtk/empathy-theme-manager.c b/libempathy-gtk/empathy-theme-manager.c
index 0dcb40a..d50154b 100644
--- a/libempathy-gtk/empathy-theme-manager.c
+++ b/libempathy-gtk/empathy-theme-manager.c
@@ -51,10 +51,17 @@
 typedef struct {
 	GSettings   *gsettings_chat;
 	gchar       *name;
-	gchar       *adium_path;
 	GtkSettings *settings;
 	GList       *boxes_views;
 	guint        emit_changed_idle;
+	gboolean     in_constructor;
+
+#ifdef HAVE_WEBKIT
+	EmpathyAdiumData *adium_data;
+	gchar *adium_variant;
+	/* list of weakref to EmpathyThemeAdium objects */
+	GList *adium_views;
+#endif
 } EmpathyThemeManagerPriv;
 
 enum {
@@ -74,6 +81,57 @@ static const gchar *themes[] = {
 
 G_DEFINE_TYPE (EmpathyThemeManager, empathy_theme_manager, G_TYPE_OBJECT);
 
+static gboolean
+theme_manager_emit_changed_idle_cb (gpointer manager)
+{
+	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
+	const gchar *adium_path = NULL;
+
+	if (priv->adium_data) {
+		adium_path = empathy_adium_data_get_path (priv->adium_data);
+	}
+	DEBUG ("Emit theme-changed with: name='%s' adium_path='%s' "
+	       "adium_variant='%s'", priv->name, adium_path,
+	       priv->adium_variant);
+
+	g_signal_emit (manager, signals[THEME_CHANGED], 0, NULL);
+	priv->emit_changed_idle = 0;
+
+	return FALSE;
+}
+
+static void
+theme_manager_emit_changed (EmpathyThemeManager *manager)
+{
+	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
+
+	/* We emit the signal in idle callback to be sure we emit it only once
+	 * in the case both the name and adium_path changed */
+	if (priv->emit_changed_idle == 0 && !priv->in_constructor) {
+		priv->emit_changed_idle = g_idle_add (
+			theme_manager_emit_changed_idle_cb, manager);
+	}
+}
+
+static void
+theme_manager_view_weak_notify_cb (gpointer data,
+				    GObject *where_the_object_was)
+{
+	GList **list = data;
+	*list = g_list_remove (*list, where_the_object_was);
+}
+
+static void
+clear_list_of_views (GList **views)
+{
+	while (*views) {
+		g_object_weak_unref ((*views)->data,
+				     theme_manager_view_weak_notify_cb,
+				     views);
+		*views = g_list_delete_link (*views, *views);
+	}
+}
+
 static void
 theme_manager_gdk_color_to_hex (GdkColor *gdk_color, gchar *str_color)
 {
@@ -135,15 +193,6 @@ theme_manager_create_irc_view (EmpathyThemeManager *manager)
 	return theme;
 }
 
-static void
-theme_manager_boxes_weak_notify_cb (gpointer data,
-				    GObject *where_the_object_was)
-{
-	EmpathyThemeManagerPriv *priv = GET_PRIV (data);
-
-	priv->boxes_views = g_list_remove (priv->boxes_views, where_the_object_was);
-}
-
 static EmpathyThemeBoxes *
 theme_manager_create_boxes_view (EmpathyThemeManager *manager)
 {
@@ -153,8 +202,8 @@ theme_manager_create_boxes_view (EmpathyThemeManager *manager)
 	theme = empathy_theme_boxes_new ();
 	priv->boxes_views = g_list_prepend (priv->boxes_views, theme);
 	g_object_weak_ref (G_OBJECT (theme),
-			   theme_manager_boxes_weak_notify_cb,
-			   manager);
+			   theme_manager_view_weak_notify_cb,
+			   &priv->boxes_views);
 
 	return theme;
 }
@@ -320,6 +369,88 @@ theme_manager_update_boxes_theme (EmpathyThemeManager *manager,
 	}
 }
 
+#ifdef HAVE_WEBKIT
+static EmpathyThemeAdium *
+theme_manager_create_adium_view (EmpathyThemeManager *manager)
+{
+	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
+	EmpathyThemeAdium *theme;
+
+	theme = empathy_theme_adium_new (priv->adium_data, priv->adium_variant);
+	priv->adium_views = g_list_prepend (priv->adium_views, theme);
+	g_object_weak_ref (G_OBJECT (theme),
+			   theme_manager_view_weak_notify_cb,
+			   &priv->adium_views);
+
+	return theme;
+}
+
+static void
+theme_manager_notify_adium_path_cb (GSettings   *gsettings_chat,
+				    const gchar *key,
+				    gpointer     user_data)
+{
+	EmpathyThemeManager     *manager = EMPATHY_THEME_MANAGER (user_data);
+	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
+	const gchar             *current_path = NULL;
+	gchar                   *new_path;
+
+	new_path = g_settings_get_string (gsettings_chat, key);
+
+	if (priv->adium_data != NULL) {
+		current_path = empathy_adium_data_get_path (priv->adium_data);
+	}
+
+	/* If path did not really changed, ignore */
+	if (!tp_strdiff (current_path, new_path)) {
+		g_free (new_path);
+		return;
+	}
+
+	/* If path does not really contains an adium path, ignore */
+	if (!empathy_adium_path_is_valid (new_path)) {
+		DEBUG ("Invalid theme path set: %s", new_path);
+		g_free (new_path);
+		return;
+	}
+
+	/* Load new theme data, we can stop tracking existing views since we
+	 * won't be able to change them live anymore */
+	clear_list_of_views (&priv->adium_views);
+	tp_clear_pointer (&priv->adium_data, empathy_adium_data_unref);
+	priv->adium_data = empathy_adium_data_new (new_path);
+
+	theme_manager_emit_changed (manager);
+
+	g_free (new_path);
+}
+
+static void
+theme_manager_notify_adium_variant_cb (GSettings   *gsettings_chat,
+				       const gchar *key,
+				       gpointer     user_data)
+{
+	EmpathyThemeManager     *manager = EMPATHY_THEME_MANAGER (user_data);
+	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
+	gchar                   *new_variant;
+	GList                   *l;
+
+	new_variant = g_settings_get_string (gsettings_chat, key);
+	if (!tp_strdiff (priv->adium_variant, new_variant)) {
+		g_free (new_variant);
+		return;
+	}
+
+	g_free (priv->adium_variant);
+	priv->adium_variant = new_variant;
+
+	for (l = priv->adium_views; l; l = l->next) {
+		empathy_theme_adium_set_variant (EMPATHY_THEME_ADIUM (l->data),
+			priv->adium_variant);
+	}
+}
+#endif /* HAVE_WEBKIT */
+
 EmpathyChatView *
 empathy_theme_manager_create_view (EmpathyThemeManager *manager)
 {
@@ -331,33 +462,8 @@ empathy_theme_manager_create_view (EmpathyThemeManager *manager)
 	DEBUG ("Using theme %s", priv->name);
 
 #ifdef HAVE_WEBKIT
-	if (strcmp (priv->name, "adium") == 0)  {
-		if (empathy_adium_path_is_valid (priv->adium_path)) {
-			static EmpathyAdiumData *data = NULL;
-			EmpathyThemeAdium *theme_adium;
-
-			if (data &&
-			    !tp_strdiff (empathy_adium_data_get_path (data),
-					 priv->adium_path)) {
-				/* Theme did not change, reuse data */
-				theme_adium = empathy_theme_adium_new (data);
-				return EMPATHY_CHAT_VIEW (theme_adium);
-			}
-
-			/* Theme changed, drop old data if any and
-			 * load a new one */
-			if (data) {
-				empathy_adium_data_unref (data);
-				data = NULL;
-			}
-
-			data = empathy_adium_data_new (priv->adium_path);
-			theme_adium = empathy_theme_adium_new (data);
-			return EMPATHY_CHAT_VIEW (theme_adium);
-		} else {
-			/* The adium path is not valid, fallback to classic theme */
-			return EMPATHY_CHAT_VIEW (theme_manager_create_irc_view (manager));
-		}
+	if (strcmp (priv->name, "adium") == 0 && priv->adium_data != NULL)  {
+		return EMPATHY_CHAT_VIEW (theme_manager_create_adium_view (manager));
 	}
 #endif
 
@@ -394,7 +500,6 @@ theme_manager_ensure_theme_exists (const gchar *name)
 }
 
 typedef enum {
-	THEME_TYPE_UNSET,
 	THEME_TYPE_IRC,
 	THEME_TYPE_BOXED,
 	THEME_TYPE_ADIUM,
@@ -403,9 +508,7 @@ typedef enum {
 static ThemeType
 theme_type (const gchar *name)
 {
-	if (name == NULL) {
-		return THEME_TYPE_UNSET;
-	} else if (!tp_strdiff (name, "classic")) {
+	if (!tp_strdiff (name, "classic")) {
 		return THEME_TYPE_IRC;
 	} else if (!tp_strdiff (name, "adium")) {
 		return THEME_TYPE_ADIUM;
@@ -414,30 +517,6 @@ theme_type (const gchar *name)
 	}
 }
 
-static gboolean
-theme_manager_emit_changed_idle_cb (gpointer manager)
-{
-	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
-
-	g_signal_emit (manager, signals[THEME_CHANGED], 0, NULL);
-	priv->emit_changed_idle = 0;
-
-	return FALSE;
-}
-
-static void
-theme_manager_emit_changed (EmpathyThemeManager *manager)
-{
-	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
-
-	/* We emit the signal in idle callback to be sure we emit it only once
-	 * in the case both the name and adium_path changed */
-	if (priv->emit_changed_idle == 0) {
-		priv->emit_changed_idle = g_idle_add (
-			theme_manager_emit_changed_idle_cb, manager);
-	}
-}
-
 static void
 theme_manager_notify_name_cb (GSettings   *gsettings_chat,
 			      const gchar *key,
@@ -478,42 +557,12 @@ theme_manager_notify_name_cb (GSettings   *gsettings_chat,
 		}
 	}
 
-	/* Do not emit theme-changed if theme type didn't change, or if it was
-	 * unset (the manager is under construction). If theme changed from a
-	 * boxed to another boxed, all view are updated in place. If theme
-	 * changed from an adium to another adium, the signal will be emited
-	 * from theme_manager_notify_adium_path_cb ()
+	/* Do not emit theme-changed if theme type didn't change. If theme
+	 * changed from a boxed to another boxed, all view are updated in place.
+	 * If theme changed from an adium to another adium, the signal will be
+	 * emited from theme_manager_notify_adium_path_cb ()
 	 */
-	if (old_type != new_type && old_type != THEME_TYPE_UNSET) {
-		theme_manager_emit_changed (manager);
-	}
-}
-
-static void
-theme_manager_notify_adium_path_cb (GSettings   *gsettings_chat,
-				    const gchar *key,
-				    gpointer     user_data)
-{
-	EmpathyThemeManager     *manager = EMPATHY_THEME_MANAGER (user_data);
-	EmpathyThemeManagerPriv *priv = GET_PRIV (manager);
-	gchar                   *adium_path = NULL;
-	gboolean                 was_set;
-
-	adium_path = g_settings_get_string (gsettings_chat, key);
-
-	if (!tp_strdiff (priv->adium_path, adium_path)) {
-		g_free (adium_path);
-		return;
-	}
-
-	was_set = (priv->adium_path != NULL);
-
-	g_free (priv->adium_path);
-	priv->adium_path = adium_path;
-
-	/* Do not emit the signal if path was not set yet (the manager is under
-	 * construction) */
-	if (was_set) {
+	if (old_type != new_type) {
 		theme_manager_emit_changed (manager);
 	}
 }
@@ -522,23 +571,22 @@ static void
 theme_manager_finalize (GObject *object)
 {
 	EmpathyThemeManagerPriv *priv = GET_PRIV (object);
-	GList                   *l;
 
 	g_object_unref (priv->gsettings_chat);
 	g_free (priv->name);
-	g_free (priv->adium_path);
-
-	for (l = priv->boxes_views; l; l = l->next) {
-		g_object_weak_unref (G_OBJECT (l->data),
-				     theme_manager_boxes_weak_notify_cb,
-				     object);
-	}
-	g_list_free (priv->boxes_views);
 
 	if (priv->emit_changed_idle != 0) {
 		g_source_remove (priv->emit_changed_idle);
 	}
 
+	clear_list_of_views (&priv->boxes_views);
+
+#ifdef HAVE_WEBKIT
+	clear_list_of_views (&priv->adium_views);
+	g_free (priv->adium_variant);
+	tp_clear_pointer (&priv->adium_data, empathy_adium_data_unref);
+#endif
+
 	G_OBJECT_CLASS (empathy_theme_manager_parent_class)->finalize (object);
 }
 
@@ -569,6 +617,7 @@ empathy_theme_manager_init (EmpathyThemeManager *manager)
 		EMPATHY_TYPE_THEME_MANAGER, EmpathyThemeManagerPriv);
 
 	manager->priv = priv;
+	priv->in_constructor = TRUE;
 
 	priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
 
@@ -581,7 +630,8 @@ empathy_theme_manager_init (EmpathyThemeManager *manager)
 				      EMPATHY_PREFS_CHAT_THEME,
 				      manager);
 
-	/* Take the adium path and track changes */
+#ifdef HAVE_WEBKIT
+	/* Take the adium path/variant and track changes */
 	g_signal_connect (priv->gsettings_chat,
 			  "changed::" EMPATHY_PREFS_CHAT_ADIUM_PATH,
 			  G_CALLBACK (theme_manager_notify_adium_path_cb),
@@ -589,6 +639,16 @@ empathy_theme_manager_init (EmpathyThemeManager *manager)
 	theme_manager_notify_adium_path_cb (priv->gsettings_chat,
 					    EMPATHY_PREFS_CHAT_ADIUM_PATH,
 					    manager);
+
+	g_signal_connect (priv->gsettings_chat,
+			  "changed::" EMPATHY_PREFS_CHAT_THEME_VARIANT,
+			  G_CALLBACK (theme_manager_notify_adium_variant_cb),
+			  manager);
+	theme_manager_notify_adium_variant_cb (priv->gsettings_chat,
+					       EMPATHY_PREFS_CHAT_THEME_VARIANT,
+					       manager);
+#endif
+	priv->in_constructor = FALSE;
 }
 
 EmpathyThemeManager *
diff --git a/libempathy/empathy-gsettings.h b/libempathy/empathy-gsettings.h
index 8d24e8b..60726d1 100644
--- a/libempathy/empathy-gsettings.h
+++ b/libempathy/empathy-gsettings.h
@@ -55,6 +55,7 @@ G_BEGIN_DECLS
 #define EMPATHY_PREFS_CHAT_SHOW_SMILEYS            "graphical-smileys"
 #define EMPATHY_PREFS_CHAT_SHOW_CONTACTS_IN_ROOMS  "show-contacts-in-rooms"
 #define EMPATHY_PREFS_CHAT_THEME                   "theme"
+#define EMPATHY_PREFS_CHAT_THEME_VARIANT           "theme-variant"
 #define EMPATHY_PREFS_CHAT_ADIUM_PATH              "adium-path"
 #define EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES "spell-checker-languages"
 #define EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED   "spell-checker-enabled"
diff --git a/src/empathy-preferences.c b/src/empathy-preferences.c
index f90724c..9aa21e8 100644
--- a/src/empathy-preferences.c
+++ b/src/empathy-preferences.c
@@ -85,6 +85,8 @@ struct _EmpathyPreferencesPriv {
 
 	GtkWidget *vbox_chat_theme;
 	GtkWidget *combobox_chat_theme;
+	GtkWidget *combobox_chat_theme_variant;
+	GtkWidget *hbox_chat_theme_variant;
 	GtkWidget *sw_chat_theme_preview;
 	EmpathyChatView *chat_theme_preview;
 	EmpathyThemeManager *theme_manager;
@@ -127,10 +129,17 @@ enum {
 	COL_THEME_NAME,
 	COL_THEME_IS_ADIUM,
 	COL_THEME_ADIUM_PATH,
+	COL_THEME_ADIUM_INFO,
 	COL_THEME_COUNT
 };
 
 enum {
+	COL_VARIANT_NAME,
+	COL_VARIANT_DEFAULT,
+	COL_VARIANT_COUNT
+};
+
+enum {
 	COL_SOUND_ENABLED,
 	COL_SOUND_NAME,
 	COL_SOUND_KEY,
@@ -734,6 +743,156 @@ preferences_preview_theme_changed_cb (EmpathyThemeManager *manager,
 }
 
 static void
+preferences_theme_variant_changed_cb (GtkComboBox        *combo,
+				      EmpathyPreferences *preferences)
+{
+	EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
+	GtkTreeIter   iter;
+
+	if (gtk_combo_box_get_active_iter (combo, &iter)) {
+		GtkTreeModel *model;
+		gchar        *name;
+
+		model = gtk_combo_box_get_model (combo);
+		gtk_tree_model_get (model, &iter,
+				    COL_VARIANT_NAME, &name,
+				    -1);
+
+		g_settings_set_string (priv->gsettings_chat,
+				       EMPATHY_PREFS_CHAT_THEME_VARIANT,
+				       name);
+
+		g_free (name);
+	}
+}
+
+static void
+preferences_theme_variant_notify_cb (GSettings   *gsettings,
+				     const gchar *key,
+				     gpointer     user_data)
+{
+	EmpathyPreferences *preferences = user_data;
+	EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
+	GtkComboBox        *combo;
+	gchar              *conf_name;
+	GtkTreeModel       *model;
+	GtkTreeIter         iter;
+	GtkTreeIter         default_iter;
+	gboolean            found_default = FALSE;
+	gboolean            found = FALSE;
+	gboolean            ok;
+
+	conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME_VARIANT);
+	combo = GTK_COMBO_BOX (priv->combobox_chat_theme_variant);
+	model = gtk_combo_box_get_model (combo);
+
+	for (ok = gtk_tree_model_get_iter_first (model, &iter);
+	     ok && !found;
+	     ok = gtk_tree_model_iter_next (model, &iter)) {
+		gchar *name;
+		gboolean is_default;
+
+		gtk_tree_model_get (model, &iter,
+				    COL_VARIANT_NAME, &name,
+				    COL_VARIANT_DEFAULT, &is_default,
+				    -1);
+
+		if (!tp_strdiff (name, conf_name)) {
+			found = TRUE;
+			gtk_combo_box_set_active_iter (combo, &iter);
+		}
+		if (is_default) {
+			found_default = TRUE;
+			default_iter = iter;
+		}
+
+		g_free (name);
+	}
+
+	/* Fallback to the first one. */
+	if (!found) {
+		if (found_default) {
+			gtk_combo_box_set_active_iter (combo, &default_iter);
+		} else if (gtk_tree_model_get_iter_first (model, &iter)) {
+			gtk_combo_box_set_active_iter (combo, &iter);
+		}
+	}
+
+	g_free (conf_name);
+}
+
+static void
+preferences_theme_variants_fill (EmpathyPreferences *preferences,
+				 GHashTable         *info)
+{
+	EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
+	GtkTreeModel *model;
+	GtkListStore *store;
+	GPtrArray    *variants;
+	const gchar  *default_variant;
+	guint         i;
+
+	model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->combobox_chat_theme_variant));
+	store = GTK_LIST_STORE (model);
+	gtk_list_store_clear (store);
+
+	variants = empathy_adium_info_get_available_variants (info);
+	default_variant = empathy_adium_info_get_default_variant (info);
+	for (i = 0; i < variants->len; i++) {
+		gchar *name = g_ptr_array_index (variants, i);
+
+		gtk_list_store_insert_with_values (store, NULL, -1,
+			COL_VARIANT_NAME, name,
+			COL_VARIANT_DEFAULT, !tp_strdiff (name, default_variant),
+			-1);
+	}
+
+	/* Select the variant from the GSetting key */
+	preferences_theme_variant_notify_cb (priv->gsettings_chat,
+					     EMPATHY_PREFS_CHAT_THEME_VARIANT,
+					     preferences);
+}
+
+static void
+preferences_theme_variants_setup (EmpathyPreferences *preferences)
+{
+	EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
+	GtkComboBox   *combo;
+	GtkCellLayout *cell_layout;
+	GtkCellRenderer *renderer;
+	GtkListStore  *store;
+
+	combo = GTK_COMBO_BOX (priv->combobox_chat_theme_variant);
+	cell_layout = GTK_CELL_LAYOUT (combo);
+
+	/* Create the model */
+	store = gtk_list_store_new (COL_VARIANT_COUNT,
+				    G_TYPE_STRING,      /* name */
+				    G_TYPE_BOOLEAN);    /* is default */
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+		COL_VARIANT_NAME, GTK_SORT_ASCENDING);
+
+	/* Add cell renderer */
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
+	gtk_cell_layout_set_attributes (cell_layout, renderer,
+		"text", COL_VARIANT_NAME, NULL);
+
+	gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
+	g_object_unref (store);
+
+	g_signal_connect (combo, "changed",
+			  G_CALLBACK (preferences_theme_variant_changed_cb),
+			  preferences);
+
+	/* Track changes of the GSetting key */
+	g_signal_connect (priv->gsettings_chat,
+			  "changed::" EMPATHY_PREFS_CHAT_THEME_VARIANT,
+			  G_CALLBACK (preferences_theme_variant_notify_cb),
+			  preferences);
+}
+
+static void
 preferences_theme_changed_cb (GtkComboBox        *combo,
 			      EmpathyPreferences *preferences)
 {
@@ -745,12 +904,14 @@ preferences_theme_changed_cb (GtkComboBox        *combo,
 		gboolean      is_adium;
 		gchar        *name;
 		gchar        *path;
+		GHashTable   *info;
 
 		model = gtk_combo_box_get_model (combo);
 		gtk_tree_model_get (model, &iter,
 				    COL_THEME_IS_ADIUM, &is_adium,
 				    COL_THEME_NAME, &name,
 				    COL_THEME_ADIUM_PATH, &path,
+				    COL_THEME_ADIUM_INFO, &info,
 				    -1);
 
 		g_settings_set_string (priv->gsettings_chat,
@@ -760,10 +921,14 @@ preferences_theme_changed_cb (GtkComboBox        *combo,
 			g_settings_set_string (priv->gsettings_chat,
 					       EMPATHY_PREFS_CHAT_ADIUM_PATH,
 					       path);
+			preferences_theme_variants_fill (preferences, info);
+			gtk_widget_show (priv->hbox_chat_theme_variant);
+		} else {
+			gtk_widget_hide (priv->hbox_chat_theme_variant);
 		}
-
 		g_free (name);
 		g_free (path);
+		tp_clear_pointer (&info, g_hash_table_unref);
 	}
 }
 
@@ -833,6 +998,8 @@ preferences_themes_setup (EmpathyPreferences *preferences)
 	GList         *adium_themes;
 	gint           i;
 
+	preferences_theme_variants_setup (preferences);
+
 	combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
 	cell_layout = GTK_CELL_LAYOUT (combo);
 
@@ -841,7 +1008,8 @@ preferences_themes_setup (EmpathyPreferences *preferences)
 				    G_TYPE_STRING,      /* Display name */
 				    G_TYPE_STRING,      /* Theme name */
 				    G_TYPE_BOOLEAN,     /* Is an Adium theme */
-				    G_TYPE_STRING);     /* Adium theme path */
+				    G_TYPE_STRING,      /* Adium theme path */
+				    G_TYPE_HASH_TABLE); /* Adium theme info */
 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
 		COL_THEME_VISIBLE_NAME, GTK_SORT_ASCENDING);
 
@@ -871,6 +1039,7 @@ preferences_themes_setup (EmpathyPreferences *preferences)
 				COL_THEME_NAME, "adium",
 				COL_THEME_IS_ADIUM, TRUE,
 				COL_THEME_ADIUM_PATH, path,
+				COL_THEME_ADIUM_INFO, info,
 				-1);
 		}
 		g_hash_table_unref (info);
@@ -972,6 +1141,8 @@ empathy_preferences_init (EmpathyPreferences *preferences)
 		"checkbutton_show_contacts_in_rooms", &priv->checkbutton_show_contacts_in_rooms,
 		"vbox_chat_theme", &priv->vbox_chat_theme,
 		"combobox_chat_theme", &priv->combobox_chat_theme,
+		"combobox_chat_theme_variant", &priv->combobox_chat_theme_variant,
+		"hbox_chat_theme_variant", &priv->hbox_chat_theme_variant,
 		"sw_chat_theme_preview", &priv->sw_chat_theme_preview,
 		"checkbutton_separate_chat_windows", &priv->checkbutton_separate_chat_windows,
 		"checkbutton_events_notif_area", &priv->checkbutton_events_notif_area,
diff --git a/src/empathy-preferences.ui b/src/empathy-preferences.ui
index 6bc17b7..2549d51 100644
--- a/src/empathy-preferences.ui
+++ b/src/empathy-preferences.ui
@@ -865,48 +865,47 @@
                             <property name="position">1</property>
                           </packing>
                         </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox" id="hbox_chat_theme_variant">
-                        <property name="visible">False</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">12</property>
                         <child>
-                          <object class="GtkLabel" id="label4">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">Theme Variant:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">combobox_chat_theme_variant</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkComboBox" id="combobox_chat_theme_variant">
-                            <property name="visible">True</property>
+                          <object class="GtkBox" id="hbox_chat_theme_variant">
                             <property name="can_focus">False</property>
+                            <property name="spacing">12</property>
+                            <child>
+                              <object class="GtkLabel" id="label4">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Variant:</property>
+                                <property name="use_underline">True</property>
+                                <property name="mnemonic_widget">combobox_chat_theme_variant</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkComboBox" id="combobox_chat_theme_variant">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">1</property>
+                            <property name="fill">True</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">True</property>
-                        <property name="position">1</property>
+                        <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
@@ -921,7 +920,7 @@
                       <packing>
                         <property name="expand">True</property>
                         <property name="fill">True</property>
-                        <property name="position">2</property>
+                        <property name="position">1</property>
                       </packing>
                     </child>
                   </object>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]