Logo Search packages:      
Sourcecode: guifications version File versions  Download package

gf_theme.c

/*
 * Guifications - The end all, be all, toaster popup plugin
 * Copyright (C) 2003-2004 Gary Kramlich
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include <glib.h>
#include <gdk/gdk.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>

#include "debug.h"
#include "util.h"
#include "xmlnode.h"

#include "gf_internal.h"
#include "gf_item.h"
#include "gf_preferences.h"
#include "gf_theme_info.h"
#include "gf_theme_ops.h"
#include "gf_utils.h"

struct _GfTheme {
      gint api_version;

      gchar *file;
      gchar *path;

      GfThemeInfo *info;
      GfThemeOptions *ops;

      GList *notifications;

      GfNotification *master;
};

#include "gf_theme.h"

static GList *probed_themes = NULL;
static GList *loaded_themes = NULL;

/***********************************************************************
 * Loading, Unloading, Probing, and Finding ...
 **********************************************************************/
GfTheme *
gf_theme_new() {
      GfTheme *theme;

      theme = g_new0(GfTheme, 1);

      return theme;
}

GfTheme *
gf_theme_new_from_file(const gchar *filename) {
      GfTheme *theme;
      gchar *contents;
      gint api_version;
      gsize length;
      xmlnode *root, *parent, *child;

      g_return_val_if_fail(filename, NULL);

      if(!g_file_get_contents(filename, &contents, &length, NULL)) {
            gaim_debug_info("Guifications", "** Error: failed to get file contents\n");
            return NULL;
      }

      if(!(root = xmlnode_from_str(contents, length))) {
            gaim_debug_info("Guifications", "** Error: Could not parse file\n");
            return NULL;
      }

      g_free(contents);

      if(!(parent = xmlnode_get_child(root, "theme"))) {
            gaim_debug_info("Guifications", "** Error: No theme element found\n");
            xmlnode_free(root);
            return NULL;
      }

      api_version = atoi(xmlnode_get_attrib(parent, "api"));
      if(api_version != GF_THEME_API_VERSION) {
            gaim_debug_info("Guifications", "** Error: Theme API version mismatch\n");
            xmlnode_free(root);
            return NULL;
      }

      /* allocate the theme */
      theme = gf_theme_new();

      /* info to know */
      theme->api_version = api_version;
      theme->file = g_strdup(filename);
      theme->path = g_path_get_dirname(filename);

      /* get the themes info */
      if(!(child = xmlnode_get_child(parent, "info"))) {
            gaim_debug_info("Guifications", "** Error: No info element found\n");
            gf_theme_unload(theme);
            xmlnode_free(root);
            return NULL;
      }

      if(!(theme->info = gf_theme_info_new_from_xmlnode(child))) {
            gaim_debug_info("Guifications", "** Error: could not load theme info\n");
            gf_theme_unload(theme);
            xmlnode_free(root);
            return NULL;
      }

      /* get the themes options */
      if(!(child = xmlnode_get_child(parent, "options"))) {
            gf_theme_unload(theme);
            xmlnode_free(root);
            return NULL;
      }

      theme->ops = gf_theme_options_new_from_xmlnode(child);

      /* get all the notifications */
      child = xmlnode_get_child(parent, "notification");

      while(child) {
            GfNotification *notification;
            notification = gf_notification_new_from_xmlnode(theme, child);

            if(notification)
                  theme->notifications = g_list_append(theme->notifications,
                                                                         notification);

            child = xmlnode_get_next_twin(child);
      }

      /* loading was successful free the xmlnode */
      xmlnode_free(root);

      return theme;
}

GfTheme *
gf_theme_find_theme_by_name(const gchar *name) {
      GfTheme *theme;
      GList *l;

      g_return_val_if_fail(name, NULL);

      for(l = loaded_themes; l; l = l->next) {
            theme = GF_THEME(l->data);

            if(!g_utf8_collate(gf_theme_info_get_name(theme->info), name))
                  return theme;
      }

      return NULL;
}

GfTheme *
gf_theme_find_theme_by_filename(const gchar *filename) {
      GfTheme *theme;
      GList *l;

      g_return_val_if_fail(filename, NULL);

      for(l = loaded_themes; l; l = l->next) {
            theme = GF_THEME(l->data);

            if(!g_ascii_strcasecmp(gf_theme_get_filename(theme), filename))
                  return theme;
      }

      return NULL;
}

gchar *
gf_theme_strip_name(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return gf_theme_info_strip_name(theme->info);
}

gboolean
gf_theme_is_loaded(const gchar *filename) {
      GfTheme *theme;
      GList *l;

      g_return_val_if_fail(filename, FALSE);

      for(l = loaded_themes; l; l = l->next) {
            theme = GF_THEME(l->data);
            if(!g_ascii_strcasecmp(filename, theme->file))
                  return TRUE;
      }

      return FALSE;
}

gboolean
gf_theme_is_probed(const gchar *filename) {
      g_return_val_if_fail(filename, FALSE);

      if(g_list_find_custom(probed_themes, filename, gf_utils_compare_strings))
            return TRUE;
      else
            return FALSE;
}

gboolean
gf_theme_save_to_file(GfTheme *theme, const gchar *filename) {
      GList *l;
      gchar *api, *data;
      FILE *fp = NULL;
      xmlnode *root, *parent, *child;

      g_return_val_if_fail(theme, FALSE);
      g_return_val_if_fail(filename, FALSE);

      root = xmlnode_new("guifications");

      parent = xmlnode_new_child(root, "theme");
      api = g_strdup_printf("%d", GF_THEME_API_VERSION);
      xmlnode_set_attrib(parent, "api", api);
      g_free(api);

      if((child = gf_theme_info_to_xmlnode(theme->info)))
            xmlnode_insert_child(parent, child);

      if((child = gf_theme_options_to_xmlnode(theme->ops)))
            xmlnode_insert_child(parent, child);

      for(l = theme->notifications; l; l = l->next) {
            if((child = gf_notification_to_xmlnode(GF_NOTIFICATION(l->data))))
                  xmlnode_insert_child(parent, child);
      }

      data = xmlnode_to_formatted_str(root, NULL);

      fp = g_fopen(filename, "wb");
      if(!fp) {
            gaim_debug_info("guifications", "Error trying to save theme %s\n", filename);
      } else {
            fprintf(fp, "<?xml version='1.0' encoding='UTF-8' ?>\n");
            if(data)
                  fprintf(fp, "%s", data);
            fclose(fp);
      }

      g_free(data);
      xmlnode_free(root);

      return TRUE;
}

void
gf_theme_destory(GfTheme *theme) {
      GList *l;

      g_return_if_fail(theme);

      theme->api_version = 0;

      if(theme->file)
            g_free(theme->file);

      if(theme->path)
            g_free(theme->path);

      if(theme->info)
            gf_theme_info_destroy(theme->info);

      if(theme->ops)
            gf_theme_options_destroy(theme->ops);

      for(l = theme->notifications; l; l = l->next)
            gf_notification_destroy(GF_NOTIFICATION(l->data));

      g_list_free(theme->notifications);
      theme->notifications = NULL;

      g_free(theme);
      theme = NULL;
}

void
gf_theme_load(const gchar *filename) {
      GfTheme *theme = NULL;

      if((theme = gf_theme_new_from_file(filename)))
            loaded_themes = g_list_append(loaded_themes, theme);
}

void
gf_theme_unload(GfTheme *theme) {
      g_return_if_fail(theme);

      loaded_themes = g_list_remove(loaded_themes, theme);

      gf_theme_destory(theme);
}

void
gf_theme_probe(const gchar *filename) {
      GfTheme *theme;
      gboolean loaded;

      g_return_if_fail(filename);

      loaded = gf_theme_is_loaded(filename);

      if(gf_theme_is_probed(filename))
            gf_theme_unprobe(filename);

      if(loaded)
            gf_theme_unload(gf_theme_find_theme_by_filename(filename));

      theme = gf_theme_new_from_file(filename);

      if(theme) {
            probed_themes = g_list_append(probed_themes, g_strdup(filename));

            if(loaded)
                  loaded_themes = g_list_append(loaded_themes, theme);
            else
                  gf_theme_destory(theme);
      }
}

void
gf_themes_probe() {
      GDir *dir;
      gchar *path = NULL, *probe_dirs[3];
      const gchar *file;
      gint i;

      probe_dirs[0] = g_build_filename(DATADIR, "pixmaps", "gaim",
                                                       "guifications", "themes", NULL);
      probe_dirs[1] = g_build_filename(gaim_user_dir(), "guifications", "themes",
                                                       NULL);
      probe_dirs[2] = NULL;

      for(i = 0; probe_dirs[i]; i++) {
            dir = g_dir_open(probe_dirs[i], 0, NULL);

            if(dir) {
                  while((file = g_dir_read_name(dir))) {
                        /* disallow themes in hidden dirs */
                        if(file[0] == '.')
                              continue;

                        path = g_build_filename(probe_dirs[i], file, "theme.xml", NULL);
                        if(path) {
                              if(g_file_test(path, G_FILE_TEST_EXISTS)) {
                                    gaim_debug_info("Guifications", "Probing %s\n", path);
                                    gf_theme_probe(path);
                              }

                              g_free(path);
                        }
                  }

                  g_dir_close(dir);
            } else if(i == 1) {
                  /* if the user theme dir doesn't exist, create it */
                  gaim_build_dir(probe_dirs[i], S_IRUSR | S_IWUSR | S_IXUSR);
            }

            g_free(probe_dirs[i]);
      }
}

void
gf_theme_unprobe(const gchar *filename) {
      GList *l, *ll;
      gchar *file;

      g_return_if_fail(filename);

      for(l = probed_themes; l; l = ll) {
            ll = l->next;

            file = (gchar*)l->data;
            if(!g_ascii_strcasecmp(file, filename)) {
                  probed_themes = g_list_remove(probed_themes, file);
                  g_free(file);
            }
      }
}

void
gf_themes_unprobe() {
      GList *l;
      gchar *file;

      for(l = probed_themes; l; l = l->next) {
            if((file = (gchar*)l->data)) {
                  gaim_debug_info("Guifications", "unprobing %s\n", file);
                  g_free(file);
            }
      }

      if(probed_themes)
            g_list_free(probed_themes);

      probed_themes = NULL;
}

/*******************************************************************************
 * Theme API
 ******************************************************************************/
gint
gf_theme_get_api_version(GfTheme *theme) {
      g_return_val_if_fail(theme, -1);

      return theme->api_version;
}

const gchar *
gf_theme_get_filename(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return theme->file;
}

const gchar *
gf_theme_get_path(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return theme->path;
}

GfNotification *
gf_theme_get_master(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return theme->master;
}

void
gf_theme_set_master(GfTheme *theme, GfNotification *notification) {
      g_return_if_fail(theme);
      g_return_if_fail(notification);

      theme->master = notification;
}

static void
gf_theme_get_supported_func(gpointer key, gpointer val, gpointer data) {
      GString *str = data;
      gchar *type = key;
      gint value = GPOINTER_TO_INT(val);

      if(strlen(str->str) != 0)
            str = g_string_append(str, ", ");

      str = g_string_append(str, type);

      if(value > 1)
            g_string_append_printf(str, " (%d)", value);
}

gchar *
gf_theme_get_supported_notifications(GfTheme *theme) {
      GfNotification *notification;
      GHashTable *table;
      GList *l;
      GString *str;
      const gchar *type;
      gchar *ret;
      gint value;
      gpointer pvalue;

      g_return_val_if_fail(theme, NULL);

      table = g_hash_table_new(g_str_hash, g_str_equal);

      for(l = theme->notifications; l; l = l->next) {
            notification = GF_NOTIFICATION(l->data);
            type = gf_notification_get_type(notification);

            if(type && type[0] == '!')
                  continue;

            pvalue = g_hash_table_lookup(table, type);
            if(pvalue)
                  value = GPOINTER_TO_INT(pvalue) + 1;
            else
                  value = 1;

            g_hash_table_replace(table, (gpointer)type, GINT_TO_POINTER(value));
      }

      str = g_string_new("");
      g_hash_table_foreach(table, gf_theme_get_supported_func, str);
      g_hash_table_destroy(table);

      ret = str->str;
      g_string_free(str, FALSE);

      return ret;
}

void
gf_theme_set_theme_info(GfTheme *theme, GfThemeInfo *info) {
      g_return_if_fail(theme);
      g_return_if_fail(info);

      if(theme->info)
            gf_theme_info_destroy(theme->info);

      theme->info = info;
}

GfThemeInfo *
gf_theme_get_theme_info(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return theme->info;
}

void
gf_theme_set_theme_options(GfTheme *theme, GfThemeOptions *ops) {
      g_return_if_fail(theme);
      g_return_if_fail(ops);

      if(theme->ops)
            gf_theme_options_destroy(theme->ops);

      theme->ops = ops;
}

GfThemeOptions *
gf_theme_get_theme_options(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return theme->ops;
}

void
gf_theme_add_notification(GfTheme *theme, GfNotification *notification) {
      const gchar *type = NULL;

      g_return_if_fail(theme);
      g_return_if_fail(notification);

      type = gf_notification_get_type(notification);
      if(!g_utf8_collate(GF_NOTIFICATION_MASTER, type)) {
            if(theme->master) {
                  const gchar *name = NULL;

                  name = gf_theme_info_get_name(theme->info);
                  gaim_debug_info("Guifications",
                                          "Theme %s already has a master notification\n",
                                          name ? name : "(NULL)");
                  return;
            } else {
                  theme->master = notification;
            }
      }

      theme->notifications = g_list_append(theme->notifications, notification);
}

void
gf_theme_remove_notification(GfTheme *theme, GfNotification *notification) {
      const gchar *type = NULL;

      g_return_if_fail(theme);
      g_return_if_fail(notification);

      type = gf_notification_get_type(notification);
      if(!g_utf8_collate(GF_NOTIFICATION_MASTER, type)) {
            gaim_debug_info("Guifications",
                                    "Master notifications can not be removed\n");
            return;
      }

      theme->notifications = g_list_remove(theme->notifications, notification);
}

GList *
gf_theme_get_notifications(GfTheme *theme) {
      g_return_val_if_fail(theme, NULL);

      return theme->notifications;
}

GList *
gf_themes_get_all() {
      return probed_themes;
}

GList *
gf_themes_get_loaded() {
      return loaded_themes;
}

void
gf_themes_unload() {
      GfTheme *theme;
      GList *l = NULL, *ll = NULL;

      for(l = loaded_themes; l; l = ll) {
            ll = l->next;

            theme = GF_THEME(l->data);

            if(theme) {
                  gf_theme_unload(theme);
                  theme = NULL;
            }
      }

      g_list_free(loaded_themes);

      loaded_themes = NULL;
}

void
gf_themes_save_loaded() {
      GfTheme *theme;
      GList *l = NULL, *s = NULL;

      for(l = loaded_themes; l; l = l->next) {
            theme = GF_THEME(l->data);

            if(theme)
                  s = g_list_append(s, theme->file);
      }

      gaim_prefs_set_string_list(GF_PREF_LOADED_THEMES, s);

      g_list_free(s);
}

void
gf_themes_load_saved(){
      GList *s = NULL;
      gchar *filename = NULL;

      for(s = gaim_prefs_get_string_list(GF_PREF_LOADED_THEMES); s; s = s->next) {
            filename = (gchar*)s->data;

            if(gf_theme_is_probed(filename))
                  gf_theme_load(filename);
      }
}

Generated by  Doxygen 1.6.0   Back to index