2 * Copyright (C) 2005-2007 Imendio AB
3 * Copyright (C) 2008-2012 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
27 #include <glib/gi18n-lib.h>
28 #include <telepathy-glib/dbus.h>
31 #include <telepathy-glib/util.h>
33 #include <libempathy/empathy-gsettings.h>
34 #include <libempathy/empathy-utils.h>
36 #include "empathy-theme-manager.h"
37 #include "empathy-chat-view.h"
38 #include "empathy-chat-text-view.h"
39 #include "empathy-theme-adium.h"
41 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
42 #include <libempathy/empathy-debug.h>
44 struct _EmpathyThemeManagerPriv
46 GSettings *gsettings_chat;
47 guint emit_changed_idle;
48 gboolean in_constructor;
50 EmpathyAdiumData *adium_data;
52 /* list of weakref to EmpathyThemeAdium objects */
62 static guint signals[LAST_SIGNAL] = { 0 };
64 G_DEFINE_TYPE (EmpathyThemeManager, empathy_theme_manager, G_TYPE_OBJECT);
67 theme_manager_emit_changed_idle_cb (gpointer manager)
69 EmpathyThemeManager *self = manager;
70 const gchar *adium_path = NULL;
72 if (self->priv->adium_data)
73 adium_path = empathy_adium_data_get_path (self->priv->adium_data);
75 DEBUG ("Emit theme-changed with: adium_path='%s' "
76 "adium_variant='%s'", adium_path, self->priv->adium_variant);
78 g_signal_emit (self, signals[THEME_CHANGED], 0, NULL);
79 self->priv->emit_changed_idle = 0;
85 theme_manager_emit_changed (EmpathyThemeManager *self)
87 /* We emit the signal in idle callback to be sure we emit it only once
88 * in the case both the name and adium_path changed */
89 if (self->priv->emit_changed_idle == 0 && !self->priv->in_constructor)
91 self->priv->emit_changed_idle = g_idle_add (
92 theme_manager_emit_changed_idle_cb, self);
97 theme_manager_view_weak_notify_cb (gpointer data,
98 GObject *where_the_object_was)
102 *list = g_list_remove (*list, where_the_object_was);
106 clear_list_of_views (GList **views)
110 g_object_weak_unref ((*views)->data,
111 theme_manager_view_weak_notify_cb,
114 *views = g_list_delete_link (*views, *views);
118 static EmpathyThemeAdium *
119 theme_manager_create_adium_view (EmpathyThemeManager *self)
121 EmpathyThemeAdium *theme;
123 theme = empathy_theme_adium_new (self->priv->adium_data, self->priv->adium_variant);
125 self->priv->adium_views = g_list_prepend (self->priv->adium_views, theme);
127 g_object_weak_ref (G_OBJECT (theme),
128 theme_manager_view_weak_notify_cb,
129 &self->priv->adium_views);
135 theme_manager_notify_adium_path_cb (GSettings *gsettings_chat,
139 EmpathyThemeManager *self = EMPATHY_THEME_MANAGER (user_data);
140 const gchar *current_path = NULL;
143 new_path = g_settings_get_string (gsettings_chat, key);
145 if (self->priv->adium_data != NULL)
146 current_path = empathy_adium_data_get_path (self->priv->adium_data);
148 /* If path did not really changed, ignore */
149 if (!tp_strdiff (current_path, new_path))
152 /* If path does not really contains an adium path, ignore */
153 if (empathy_adium_path_is_valid (new_path))
157 else if (empathy_theme_manager_find_theme (new_path) != NULL)
159 new_path = empathy_theme_manager_find_theme (new_path);
163 g_warning ("Do not understand theme: %s", new_path);
167 /* Load new theme data, we can stop tracking existing views since we
168 * won't be able to change them live anymore */
169 clear_list_of_views (&self->priv->adium_views);
170 tp_clear_pointer (&self->priv->adium_data, empathy_adium_data_unref);
171 self->priv->adium_data = empathy_adium_data_new (new_path);
173 theme_manager_emit_changed (self);
180 theme_manager_notify_adium_variant_cb (GSettings *gsettings_chat,
184 EmpathyThemeManager *self = EMPATHY_THEME_MANAGER (user_data);
188 new_variant = g_settings_get_string (gsettings_chat, key);
189 if (!tp_strdiff (self->priv->adium_variant, new_variant))
191 g_free (new_variant);
195 g_free (self->priv->adium_variant);
196 self->priv->adium_variant = new_variant;
198 for (l = self->priv->adium_views; l; l = l->next)
200 empathy_theme_adium_set_variant (EMPATHY_THEME_ADIUM (l->data),
201 self->priv->adium_variant);
206 empathy_theme_manager_create_view (EmpathyThemeManager *self)
208 g_return_val_if_fail (EMPATHY_IS_THEME_MANAGER (self), NULL);
210 if (self->priv->adium_data != NULL)
211 return EMPATHY_CHAT_VIEW (theme_manager_create_adium_view (self));
213 g_return_val_if_reached (NULL);
217 theme_manager_finalize (GObject *object)
219 EmpathyThemeManager *self = (EmpathyThemeManager *) object;
221 g_object_unref (self->priv->gsettings_chat);
223 if (self->priv->emit_changed_idle != 0)
224 g_source_remove (self->priv->emit_changed_idle);
226 clear_list_of_views (&self->priv->adium_views);
227 g_free (self->priv->adium_variant);
228 tp_clear_pointer (&self->priv->adium_data, empathy_adium_data_unref);
230 G_OBJECT_CLASS (empathy_theme_manager_parent_class)->finalize (object);
234 empathy_theme_manager_class_init (EmpathyThemeManagerClass *klass)
236 GObjectClass *object_class = G_OBJECT_CLASS (klass);
238 signals[THEME_CHANGED] = g_signal_new ("theme-changed",
239 G_OBJECT_CLASS_TYPE (object_class),
243 g_cclosure_marshal_generic,
247 g_type_class_add_private (object_class, sizeof (EmpathyThemeManagerPriv));
249 object_class->finalize = theme_manager_finalize;
253 empathy_theme_manager_init (EmpathyThemeManager *self)
255 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
256 EMPATHY_TYPE_THEME_MANAGER, EmpathyThemeManagerPriv);
258 self->priv->in_constructor = TRUE;
260 self->priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
262 /* Take the adium path/variant and track changes */
263 g_signal_connect (self->priv->gsettings_chat,
264 "changed::" EMPATHY_PREFS_CHAT_ADIUM_PATH,
265 G_CALLBACK (theme_manager_notify_adium_path_cb), self);
267 theme_manager_notify_adium_path_cb (self->priv->gsettings_chat,
268 EMPATHY_PREFS_CHAT_ADIUM_PATH, self);
270 g_signal_connect (self->priv->gsettings_chat,
271 "changed::" EMPATHY_PREFS_CHAT_THEME_VARIANT,
272 G_CALLBACK (theme_manager_notify_adium_variant_cb), self);
274 theme_manager_notify_adium_variant_cb (self->priv->gsettings_chat,
275 EMPATHY_PREFS_CHAT_THEME_VARIANT, self);
277 self->priv->in_constructor = FALSE;
280 EmpathyThemeManager *
281 empathy_theme_manager_dup_singleton (void)
283 static EmpathyThemeManager *manager = NULL;
287 manager = g_object_new (EMPATHY_TYPE_THEME_MANAGER, NULL);
288 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer *) &manager);
293 return g_object_ref (manager);
297 find_themes (GList **list, const gchar *dirpath)
300 GError *error = NULL;
301 const gchar *name = NULL;
302 GHashTable *info = NULL;
304 dir = g_dir_open (dirpath, 0, &error);
307 name = g_dir_read_name (dir);
313 path = g_build_path (G_DIR_SEPARATOR_S, dirpath, name, NULL);
314 if (empathy_adium_path_is_valid (path))
316 info = empathy_adium_info_new (path);
319 *list = g_list_prepend (*list, info);
323 name = g_dir_read_name (dir);
330 DEBUG ("Error opening %s: %s\n", dirpath, error->message);
331 g_error_free (error);
336 empathy_theme_manager_get_adium_themes (void)
338 GList *themes_list = NULL;
339 gchar *userpath = NULL;
340 const gchar *const *paths = NULL;
343 userpath = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
344 "adium/message-styles", NULL);
345 find_themes (&themes_list, userpath);
348 paths = g_get_system_data_dirs ();
349 for (i = 0; paths[i] != NULL; i++)
351 userpath = g_build_path (G_DIR_SEPARATOR_S, paths[i],
352 "adium/message-styles", NULL);
353 find_themes (&themes_list, userpath);
361 empathy_theme_manager_find_theme (const gchar *name)
364 const gchar * const *paths;
367 /* look in EMPATHY_SRCDIR */
368 path = g_strjoin (NULL,
369 g_getenv ("EMPATHY_SRCDIR"),
372 ".AdiumMessageStyle",
375 DEBUG ("Trying '%s'", path);
377 if (empathy_adium_path_is_valid (path))
382 /* look in user dir */
383 path = g_strjoin (NULL,
384 g_get_user_data_dir (),
385 "/adium/message-styles/",
387 ".AdiumMessageStyle",
390 DEBUG ("Trying '%s'", path);
392 if (empathy_adium_path_is_valid (path))
397 /* look in system dirs */
398 paths = g_get_system_data_dirs ();
400 for (i = 0; paths[i] != NULL; i++)
402 path = g_strjoin (NULL,
404 "/adium/message-styles/",
406 ".AdiumMessageStyle",
409 DEBUG ("Trying '%s'", path);
411 if (empathy_adium_path_is_valid (path))
421 empathy_theme_manager_dup_theme_name_from_path (const gchar *path)
423 gchar *fullname, *result;
429 fullname = g_path_get_basename (path);
430 if (!g_str_has_suffix (fullname, ".AdiumMessageStyle"))
433 tmp = g_strsplit (fullname, ".AdiumMessageStyle", 0);
434 result = g_strdup (tmp[0]);