/* This program was written under the GPL by Jonathan Blandford <jrb@gnome.org>
 */

#include <config.h>

#include <string.h>
#include <gconf/gconf-client.h>
#include <glade/glade.h>
#include <libgnomevfs/gnome-vfs-async-ops.h>
#include <libgnomevfs/gnome-vfs-ops.h>
#include <libgnomevfs/gnome-vfs-utils.h>

#include <libwindow-settings/gnome-wm-manager.h>

#include "gnome-theme-info.h"
#include "gnome-theme-save.h"
#include "capplet-util.h"
#include "activate-settings-daemon.h"
#include "gconf-property-editor.h"
#include "file-transfer-dialog.h"
#include "gnome-theme-manager.h"
#include "gnome-theme-details.h"
#include "gnome-theme-installer.h"
#include <theme-thumbnail.h>
#include <gnome-theme-apply.h>


#define MAX_ELEMENTS_BEFORE_SCROLLING 3

/* Events: There are two types of change events we worry about.  The first is
 * when the theme settings change.  In this case, we can quickly update the UI
 * to reflect.  The other is when the themes themselves change.
 *
 * The code in gnome-theme-manager.c will update the main dialog and proxy the
 * update notifications for the details dialog.
 */

enum
{
  META_THEME_NAME_COLUMN = THEME_NAME_COLUMN,
  META_THEME_ID_COLUMN = THEME_ID_COLUMN,
  META_THEME_FLAG_COLUMN = THEME_FLAG_COLUMN,
  META_THEME_PIXBUF_COLUMN,
  META_N_COLUMNS
};

GtkTargetEntry drop_types[] =
{
  {"text/uri-list", 0, TARGET_URI_LIST},
  {"_NETSCAPE_URL", 0, TARGET_NS_URL}
};

gint n_drop_types = sizeof (drop_types) / sizeof (GtkTargetEntry);

static gboolean setting_model = FALSE;
static guint update_settings_from_gconf_idle_id = 0;
static guint theme_changed_idle_id = 0;
static guint pixbuf_idle_id = 0;
static gboolean loading_themes;
static gboolean reload_themes;
static gboolean initial_meta_theme_set = FALSE;
static GdkPixbuf *default_image = NULL;
static GdkPixbuf *broken_image = NULL;
static gboolean themes_loaded = FALSE;
static gboolean reverted = FALSE;

static GnomeThemeMetaInfo custom_meta_theme_info;
static GnomeThemeMetaInfo initial_meta_theme_info;

const char *meta_theme_default_name = NULL; 
const char *gtk_theme_default_name = NULL; 
const char *window_theme_default_name = NULL; 
const char *icon_theme_default_name = NULL; 


/* Function Prototypes */
static void      add_pixbuf_idle                 (void);
static void      load_meta_themes                (GtkTreeView        *tree_view,
						  GList              *meta_theme_list);
static void      meta_theme_setup_info           (GnomeThemeMetaInfo *meta_theme_info,
						  GladeXML           *dialog);
static void      meta_theme_selection_changed    (GtkTreeSelection   *selection,
						  GladeXML           *dialog);
static void      update_themes_from_disk         (GladeXML           *dialog);
static void      update_settings_from_gconf      (void);
static void      gtk_theme_key_changed           (GConfClient        *client,
						  guint               cnxn_id,
						  GConfEntry         *entry,
						  gpointer            user_data);
static void      window_settings_changed         (GnomeWindowManager *window_manager,
						  GladeXML           *dialog);
static void      icon_key_changed                (GConfClient        *client,
						  guint               cnxn_id,
						  GConfEntry         *entry,
						  gpointer            user_data);
static void      font_key_changed                (GConfClient        *client,
						  guint               cnxn_id,
						  GConfEntry         *entry,
						  gpointer            user_data);
static void      theme_changed_func              (gpointer            uri,
						  gpointer            user_data);
static void      cb_dialog_response              (GtkDialog          *dialog,
						  gint                response_id);
static void      setup_meta_tree_view            (GtkTreeView        *tree_view,
						  GCallback           changed_callback,
						  GladeXML           *dialog);
static void      setup_dialog                    (GladeXML           *dialog);


typedef struct {
  gchar *theme_id;
  GtkTreeModel *model;
  gboolean cancelled;
} PixbufAsyncData;

static void
pixbuf_async_func (GdkPixbuf *pixbuf,
		   gpointer   data)
{
  PixbufAsyncData *pixbuf_async_data = data;
  gchar *theme_id;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gboolean valid;

  theme_id = pixbuf_async_data->theme_id;
  model = pixbuf_async_data->model;

  for (valid = gtk_tree_model_get_iter_first (model, &iter);
       valid;
       valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar *test_theme_id;
      gtk_tree_model_get (model, &iter,
			  META_THEME_ID_COLUMN, &test_theme_id,
			  -1);
      if (theme_id && test_theme_id && !strcmp (theme_id, test_theme_id))
	{
	  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
			      META_THEME_PIXBUF_COLUMN, pixbuf ? pixbuf : broken_image,
			      -1);
	  g_free (test_theme_id);
	  break;
	}
      g_free (test_theme_id);
    }

  add_pixbuf_idle ();
}

static void
pixbuf_async_data_free (gpointer data)
{
  PixbufAsyncData *pixbuf_async_data = data;

  g_object_unref (pixbuf_async_data->model);
  g_free (pixbuf_async_data->theme_id);
  g_free (pixbuf_async_data);
}

static gboolean
pixbuf_idle_func (gpointer data)
{
  GladeXML *dialog;
  GtkWidget *tree_view;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gboolean valid;

  pixbuf_idle_id = 0;

  if (reload_themes) {
    GladeXML *dialog;

    reload_themes = FALSE;
    loading_themes = FALSE;

    dialog = gnome_theme_manager_get_theme_dialog ();
    update_themes_from_disk (dialog);
    return FALSE;
  }

  dialog = gnome_theme_manager_get_theme_dialog ();
  tree_view = WID ("meta_theme_treeview");
  model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));

  for (valid = gtk_tree_model_get_iter_first (model, &iter);
       valid;
       valid = gtk_tree_model_iter_next (model, &iter))
    {
      GdkPixbuf *pixbuf = NULL;
      gchar *theme_id = NULL;

      gtk_tree_model_get (model, &iter,
			  META_THEME_PIXBUF_COLUMN, &pixbuf,
			  -1);
      if (pixbuf == default_image)
	{
	  PixbufAsyncData *pixbuf_async_data;
	  GnomeThemeMetaInfo *meta_theme_info;

	  gtk_tree_model_get (model, &iter,
			      META_THEME_ID_COLUMN, &theme_id,
			      -1);
	  if (theme_id == NULL)
	    {
	      meta_theme_info = &custom_meta_theme_info;
	    }
	  else
	    {
	      meta_theme_info = gnome_theme_meta_info_find (theme_id);
	    }

	  /* We should always have a metatheme file */
	  g_assert (meta_theme_info);

	  pixbuf_async_data = g_new (PixbufAsyncData, 1);
	  pixbuf_async_data->theme_id = theme_id;
	  pixbuf_async_data->model = model;
	  pixbuf_async_data->cancelled = FALSE;
	  g_object_ref (model);
	  generate_theme_thumbnail_async (meta_theme_info,
					  pixbuf_async_func,
					  pixbuf_async_data,
					  pixbuf_async_data_free);

	  return FALSE;
	}
    }

  /* If we're done loading all the main themes, lets initialize the details
   * dialog if it hasn't been done yet.  If it has, then this call is harmless.
   */
  gnome_theme_details_init ();
  loading_themes = FALSE;

  if (reload_themes) {
    GladeXML *dialog;

    reload_themes = FALSE;
    loading_themes = FALSE;

    dialog = gnome_theme_manager_get_theme_dialog ();
    update_themes_from_disk (dialog);
  }

  return FALSE;
}

/* FIXME: we need a way to cancel the pixbuf loading if we get a theme updating
 * during the pixbuf generation.
 */
static void
add_pixbuf_idle (void)
{
  if (pixbuf_idle_id)
    return;

  pixbuf_idle_id = g_idle_add_full (G_PRIORITY_LOW,
				    pixbuf_idle_func,
				    NULL, NULL);
}

static gint
sort_meta_theme_list_func (gconstpointer  a,
			   gconstpointer  b)
{
  const GnomeThemeMetaInfo *a_meta_theme_info = a;
  const GnomeThemeMetaInfo *b_meta_theme_info = b;
  guint a_flag = 0;
  guint b_flag = 0;

  g_assert (a_meta_theme_info->name);
  g_assert (b_meta_theme_info->name);

  if (meta_theme_default_name && strcmp (meta_theme_default_name, a_meta_theme_info->name) == 0)
    a_flag |= THEME_FLAG_DEFAULT;
  if (meta_theme_default_name && strcmp (meta_theme_default_name, b_meta_theme_info->name) == 0)
    b_flag |= THEME_FLAG_DEFAULT;

  return gnome_theme_manager_sort_func (a_meta_theme_info->readable_name,
					b_meta_theme_info->readable_name,
					a_flag,
					b_flag);
}


/* Loads up a list of GnomeThemeMetaInfo.
 */
static void
load_meta_themes (GtkTreeView *tree_view,
		  GList       *meta_theme_list)
{
  GList *list;
  GtkTreeModel *model;
  GtkWidget *swindow;
  GtkTreeIter iter;
  gchar *name;
  gboolean valid;
  guint flag;
  gint i = 0;
  GConfClient *client;
  gchar *current_gtk_theme;
  gchar *current_window_theme;
  gchar *current_icon_theme;
  GnomeWindowManager *window_manager;
  GnomeWMSettings wm_settings;
  static gboolean first_time = TRUE;

  swindow = GTK_WIDGET (tree_view)->parent;
  model = gtk_tree_view_get_model (tree_view);
  g_assert (model);

  setting_model = TRUE;

  client = gconf_client_get_default ();

  current_gtk_theme = gconf_client_get_string (client, GTK_THEME_KEY, NULL);
  current_icon_theme = gconf_client_get_string (client, ICON_THEME_KEY, NULL);
  g_object_unref (client);

  window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ()));
  wm_settings.flags = GNOME_WM_SETTING_THEME;

  if (window_manager)
    {
      gnome_window_manager_get_settings (window_manager, &wm_settings);
      current_window_theme = g_strdup (wm_settings.theme);
    }
  else
    current_window_theme = g_strdup (window_theme_default_name);

  /* FIXME: What do we really do when there is no theme? */
  if (current_icon_theme == NULL)
    current_icon_theme = g_strdup (icon_theme_default_name);
  if (current_gtk_theme == NULL)
    current_gtk_theme = g_strdup (gtk_theme_default_name);

  /* handle first time */
  if (first_time)
    {
      for (list = meta_theme_list; list; list = list->next)
	{
	  GnomeThemeMetaInfo *theme_info = list->data;

	  if ((theme_info->gtk_theme_name && !strcmp (theme_info->gtk_theme_name, gtk_theme_default_name)) &&
	      (theme_info->metacity_theme_name && !strcmp (theme_info->metacity_theme_name, window_theme_default_name)) &&
	      (theme_info->icon_theme_name && !strcmp (theme_info->icon_theme_name, icon_theme_default_name)))
	    {
	      meta_theme_default_name = g_strdup (theme_info->name);
	      break;
	    }
	}
    }
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
				  GTK_POLICY_NEVER, GTK_POLICY_NEVER);
  gtk_widget_set_usize (swindow, -1, -1);

  /* Sort meta_theme_list to be in the same order of the current data.  This way
   * we can walk through them together. */
  meta_theme_list = g_list_sort (meta_theme_list, sort_meta_theme_list_func);
  list = meta_theme_list;
  valid = gtk_tree_model_get_iter_first (model, &iter);

  while (valid || list != NULL)
    {
      GnomeThemeMetaInfo *list_meta_theme_info = NULL;
      GnomeThemeMetaInfo *model_meta_theme_info = NULL;
      gchar *blurb;
      gboolean list_is_default = FALSE;
      GdkPixbuf *pixbuf = NULL;
      gboolean delete_it = FALSE;
      gboolean set_it = FALSE;
      GtkTreeIter iter_to_set;

      /* Check info on the list */
      if (list)
	{
	  list_meta_theme_info = list->data;
	  if (meta_theme_default_name && strcmp (meta_theme_default_name, list_meta_theme_info->name) == 0)
	    list_is_default = TRUE;
	  else
	    list_is_default = FALSE;
	}

      if (valid)
	{
	  gtk_tree_model_get (model, &iter,
			      META_THEME_ID_COLUMN, &name,
			      META_THEME_FLAG_COLUMN, &flag,
			      -1);
	  if (name)
	    {
	      model_meta_theme_info = gnome_theme_meta_info_find (name);
	      g_free (name);

	      /* The theme was removed, and we haven't removed it from the list yet. */
	      if (model_meta_theme_info == NULL)
		{
		  delete_it = TRUE;
		  goto end_of_loop;
		}
	    }
	}

      /* start comparing values */
      if (list && valid)
	{
	  gint compare_val;

	  if (flag & THEME_FLAG_CUSTOM)
	    {
	      /* We can always skip the custom row, as it's never in the list */
	      valid = gtk_tree_model_iter_next (model, &iter);
	      i++;
	      goto end_of_loop;
	    }

	  compare_val = gnome_theme_manager_sort_func (model_meta_theme_info->readable_name, list_meta_theme_info->readable_name,
						       flag, list_is_default ? THEME_FLAG_DEFAULT : 0);

	  if (compare_val < 0)
	    {
	      delete_it = TRUE;
	      goto end_of_loop;
	    }
	  else if (compare_val == 0)
	    {
	      set_it = TRUE;
	      iter_to_set = iter;
	      valid = gtk_tree_model_iter_next (model, &iter);
	    }
	  else
	    {
	      /* we insert a new item */
	      set_it = TRUE;
	      gtk_list_store_insert_before (GTK_LIST_STORE (model), &iter_to_set, &iter);
	    }
	}
      else if (list)
	{
	  /* we append a new item */
	  set_it = TRUE;
	  gtk_list_store_append (GTK_LIST_STORE (model), &iter_to_set);
	}
      else if (valid)
	{
	  /* It's a dead item. */
	  delete_it = TRUE;
	}

    end_of_loop:
      if (delete_it)
	{
	  GtkTreeIter iter_to_remove;
	  iter_to_remove = iter;
	  valid = gtk_tree_model_iter_next (model, &iter);
	  gtk_list_store_remove (GTK_LIST_STORE (model), &iter_to_remove);
	}
      if (set_it)
	{
	  /* We reset the blurb in case it has changed */
	  blurb = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
					   list_meta_theme_info->readable_name, list_meta_theme_info->comment);

	  if (i <= MAX_ELEMENTS_BEFORE_SCROLLING) {
	    pixbuf = generate_theme_thumbnail (list_meta_theme_info, FALSE);
	    if (pixbuf == NULL)
	      pixbuf = broken_image;
	  } else {
	    pixbuf = default_image;
	  }

	  gtk_list_store_set (GTK_LIST_STORE (model), &iter_to_set,
			      META_THEME_PIXBUF_COLUMN, pixbuf,
			      META_THEME_NAME_COLUMN, blurb,
			      META_THEME_ID_COLUMN, list_meta_theme_info->name,
			      META_THEME_FLAG_COLUMN, list_is_default ? THEME_FLAG_DEFAULT : 0,
			      -1);
	  g_free (blurb);

	  list = list->next;
	  i++;
	}
      if (i == MAX_ELEMENTS_BEFORE_SCROLLING)
	{
	  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
					  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	}
    }

  add_pixbuf_idle ();

  g_free (current_gtk_theme);
  g_free (current_icon_theme);
  g_free (current_window_theme);
  first_time = FALSE;
  setting_model = FALSE;
}

static void
meta_theme_setup_info (GnomeThemeMetaInfo *meta_theme_info,
		       GladeXML           *dialog)
{
  GtkWidget *notebook;

  notebook = WID ("meta_theme_notebook");

  if (meta_theme_info == NULL)
    {
      gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
    }
  else
    {
      if (meta_theme_info->application_font != NULL)
	{
	  if (meta_theme_info->background_image != NULL)
	    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 3);
	  else
	    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1);
	}
      else
	{
	  if (meta_theme_info->background_image != NULL)
	    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 2);
	  else
	    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
	}
    }
}

static void
meta_theme_selection_changed (GtkTreeSelection *selection,
			      GladeXML         *dialog)
{
  GnomeThemeMetaInfo *meta_theme_info;
  GtkTreeIter iter;
  gchar *meta_theme_name;
  GtkTreeModel *model;
  gchar *current_gtk_theme;
  gchar *current_window_theme;
  gchar *current_icon_theme;
  GConfClient *client;
  GnomeWindowManager *window_manager;
  GnomeWMSettings wm_settings;
  
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      gtk_tree_model_get (model, &iter,
			  META_THEME_ID_COLUMN, &meta_theme_name,
			  -1);
    }
  else
    {
      /* I probably just added a row. */
      return;
    }

  if (meta_theme_name)
    {
      meta_theme_info = gnome_theme_meta_info_find (meta_theme_name);
      g_free (meta_theme_name);
    }
  else
    {
      meta_theme_info = &custom_meta_theme_info;
    }
  meta_theme_setup_info (meta_theme_info, dialog);

  if (setting_model)
    return;

  if (meta_theme_info) 
    gnome_meta_theme_set (meta_theme_info);
  
  if (!themes_loaded) {
    client = gconf_client_get_default ();

    /* Get the settings */
    current_gtk_theme = gconf_client_get_string (client, GTK_THEME_KEY, NULL);
    current_icon_theme = gconf_client_get_string (client, ICON_THEME_KEY, NULL);
    g_object_unref (client);

    window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ()));
    wm_settings.flags = GNOME_WM_SETTING_THEME;
    if (window_manager) {
      gnome_window_manager_get_settings (window_manager, &wm_settings);
      current_window_theme = g_strdup (wm_settings.theme);
    } else
      current_window_theme = g_strdup ("");

	initial_meta_theme_info.name = g_strdup ("__Initial Theme__");
	initial_meta_theme_info.gtk_theme_name = g_strdup (current_gtk_theme);
	initial_meta_theme_info.metacity_theme_name = g_strdup (current_window_theme);
 	initial_meta_theme_info.icon_theme_name = g_strdup (current_icon_theme);
	themes_loaded = TRUE;
  } else {
	  if (!reverted) {
        gtk_widget_set_sensitive(WID("meta_theme_revert_button"),TRUE);
	  } else {
		reverted = FALSE;
	  }
  }
}

/* This function will adjust the list to reflect the current theme
 * situation.  It is called after the themes change on disk.  Currently, it
 * recreates the entire list.
 */
static void
update_themes_from_disk (GladeXML *dialog)
{
  GList *theme_list;

  if (loading_themes) {
    reload_themes = TRUE;
    return;
  }

  loading_themes = TRUE;

  theme_list = gnome_theme_meta_info_find_all ();
  gtk_widget_show (WID ("meta_theme_hbox"));
  load_meta_themes (GTK_TREE_VIEW (WID ("meta_theme_treeview")), theme_list);
  g_list_free (theme_list);

  update_settings_from_gconf ();
}

static void
add_custom_row_to_meta_theme (const gchar  *current_gtk_theme,
			      const gchar  *current_window_theme,
			      const gchar  *current_icon_theme,
			      gboolean      select)
{
  GladeXML *dialog;
  GtkWidget *tree_view;
  GtkTreeModel *model;
  GtkTreePath *path;
  GtkTreeIter iter;
  gboolean valid;
  gchar *blurb;
  GdkPixbuf *pixbuf;

  dialog = gnome_theme_manager_get_theme_dialog ();
  tree_view = WID ("meta_theme_treeview");
  model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));

  g_free (custom_meta_theme_info.gtk_theme_name);
  custom_meta_theme_info.gtk_theme_name = g_strdup (current_gtk_theme);
  g_free (custom_meta_theme_info.metacity_theme_name);
  custom_meta_theme_info.metacity_theme_name = g_strdup (current_window_theme);
  g_free (custom_meta_theme_info.icon_theme_name);
  custom_meta_theme_info.icon_theme_name = g_strdup (current_icon_theme);
  g_free (custom_meta_theme_info.name);
  custom_meta_theme_info.name = g_strdup ("__Custom Theme__");

  for (valid = gtk_tree_model_get_iter_first (model, &iter);
       valid;
       valid = gtk_tree_model_iter_next (model, &iter))
    {
      guint theme_flags = 0;

      gtk_tree_model_get (model, &iter,
			  META_THEME_FLAG_COLUMN, &theme_flags,
			  -1);
      if (theme_flags & THEME_FLAG_CUSTOM)
	break;

    }

  /* if we found a custom row and broke out of the list above, valid will be
   * TRUE.  If we didn't, we need to add a new iter.
   */
  if (!valid)
    gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);

  /* set the values of the Custom theme. */
  blurb = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
				   _("Custom theme"), _("You can save this theme by pressing the Save Theme button."));

  /* Invalidate the cache because the custom theme has potentially changed */
  /* Commented out because it does odd things */
  /*theme_thumbnail_invalidate_cache (&custom_meta_theme_info);*/

  pixbuf = generate_theme_thumbnail (&custom_meta_theme_info, TRUE);
  if (pixbuf == NULL)
    pixbuf = default_image;
  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
		      META_THEME_PIXBUF_COLUMN, pixbuf,
		      META_THEME_NAME_COLUMN, blurb,
		      META_THEME_FLAG_COLUMN, THEME_FLAG_CUSTOM,
		      -1);

  gtk_widget_set_sensitive (WID ("meta_theme_save_button"), TRUE);
  path = gtk_tree_model_get_path (model, &iter);
  if (select)
    gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), path, NULL, FALSE);
  gtk_tree_path_free (path);
  g_free (blurb);
}

static void
remove_custom_row_from_meta_theme (void)
{
  GladeXML *dialog;
  GtkWidget *tree_view;
  GtkTreeModel *model;
  GtkTreeIter iter;
  GtkTreeIter next_iter;
  gboolean valid;

  dialog = gnome_theme_manager_get_theme_dialog ();
  tree_view = WID ("meta_theme_treeview");
  model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));

  valid = gtk_tree_model_get_iter_first (model, &iter);
  while (valid)
    {
      guint theme_flags = 0;

      next_iter = iter;
      valid = gtk_tree_model_iter_next (model, &next_iter);

      gtk_tree_model_get (model, &iter,
			  META_THEME_FLAG_COLUMN, &theme_flags,
			  -1);

      if (theme_flags & THEME_FLAG_CUSTOM)
	{
	  gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
	}
      iter = next_iter;
    }
  g_free (custom_meta_theme_info.gtk_theme_name);
  g_free (custom_meta_theme_info.metacity_theme_name);
  g_free (custom_meta_theme_info.icon_theme_name);
  g_free (custom_meta_theme_info.name);

  gtk_widget_set_sensitive (WID ("meta_theme_save_button"), FALSE);

  custom_meta_theme_info.gtk_theme_name = NULL;
  custom_meta_theme_info.metacity_theme_name = NULL;
  custom_meta_theme_info.icon_theme_name = NULL;
  custom_meta_theme_info.name = NULL;
}

static gboolean
themes_equal (GnomeThemeMetaInfo *a, GnomeThemeMetaInfo *b)
{
  if (!a->gtk_theme_name ||
      !b->gtk_theme_name ||
      strcmp (a->gtk_theme_name, b->gtk_theme_name))
    return FALSE;
  if (!a->metacity_theme_name ||
      !b->metacity_theme_name ||
      strcmp (a->metacity_theme_name, b->metacity_theme_name))
    return FALSE;
  if (!a->icon_theme_name ||
      !b->icon_theme_name ||
      strcmp (a->icon_theme_name, b->icon_theme_name))
    return FALSE;
  return TRUE;
}


/* Sets the list to point to the current theme.  Also creates the 'Custom Theme'
 * field if needed */
static gboolean
update_settings_from_gconf_idle (gpointer data)
{
  GConfClient *client;
  gchar *current_gtk_theme;
  gchar *current_window_theme;
  gchar *current_icon_theme;
  GnomeWindowManager *window_manager;
  GnomeWMSettings wm_settings;
  GtkWidget *tree_view;
  GtkTreeModel *model;
  GtkTreeIter iter;
  GladeXML *dialog;
  gboolean valid;
  gboolean current_theme_saved;
  gboolean initial_theme_saved;
  static gboolean first_time_run = TRUE;

  client = gconf_client_get_default ();

  /* Get the settings */
  current_gtk_theme = gconf_client_get_string (client, GTK_THEME_KEY, NULL);
  current_icon_theme = gconf_client_get_string (client, ICON_THEME_KEY, NULL);
  g_object_unref (client);

  window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ()));
  wm_settings.flags = GNOME_WM_SETTING_THEME;
  if (window_manager) {
    gnome_window_manager_get_settings (window_manager, &wm_settings);
    current_window_theme = g_strdup (wm_settings.theme);
  } else
    current_window_theme = g_strdup ("");

  /* True if the current or initial theme has a meta theme that it matches. */
  current_theme_saved = FALSE;
  initial_theme_saved = FALSE;

  /* Walk the tree looking for the current one. */
  dialog = gnome_theme_manager_get_theme_dialog ();
  tree_view = WID ("meta_theme_treeview");
  g_assert (tree_view);
  model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));

  for (valid = gtk_tree_model_get_iter_first (model, &iter);
       valid;
       valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar *row_theme_id = NULL;
      guint row_theme_flags = 0;
      GnomeThemeMetaInfo *meta_theme_info;

      gtk_tree_model_get (model, &iter,
			  META_THEME_ID_COLUMN, &row_theme_id,
			  META_THEME_FLAG_COLUMN, &row_theme_flags,
			  -1);

      if (row_theme_id) {
	meta_theme_info = gnome_theme_meta_info_find (row_theme_id);
      }
      else {
	continue;
      }
      g_free (row_theme_id);
      if (row_theme_flags & THEME_FLAG_CUSTOM) {
	continue;
      }
      
      if (initial_meta_theme_set && themes_equal (&initial_meta_theme_info, meta_theme_info))
	initial_theme_saved = TRUE;
      if (! strcmp (current_gtk_theme, meta_theme_info->gtk_theme_name) &&
	  (window_manager == NULL ||
	   ! strcmp (current_window_theme, meta_theme_info->metacity_theme_name)) &&
	  ! strcmp (current_icon_theme, meta_theme_info->icon_theme_name))
	{
	  GtkTreePath *path;
	  GtkTreePath *cursor_path;
	  gboolean cursor_same = FALSE;

	  gtk_tree_view_get_cursor (GTK_TREE_VIEW (tree_view), &cursor_path, NULL);
	  path = gtk_tree_model_get_path (model, &iter);
	  if (cursor_path && gtk_tree_path_compare (path, cursor_path) == 0)
	    cursor_same = TRUE;

	  gtk_tree_path_free (cursor_path);

	  if (!cursor_same)
	    {
	      gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), path, NULL, FALSE);
	    }
	  gtk_tree_path_free (path);
	  current_theme_saved = TRUE;

	  break;
	}
    }

  if (!current_theme_saved && first_time_run)
    {
      initial_meta_theme_set = TRUE;
      initial_meta_theme_info.name = g_strdup ("__Initial Theme__");
      initial_meta_theme_info.gtk_theme_name = g_strdup (current_gtk_theme);
      initial_meta_theme_info.metacity_theme_name = g_strdup (current_window_theme);
      initial_meta_theme_info.icon_theme_name = g_strdup (current_icon_theme);
    }
  first_time_run = FALSE;
  

  if (!current_theme_saved)
    {
      add_custom_row_to_meta_theme (current_gtk_theme,
				    current_window_theme,
				    current_icon_theme,
				    TRUE);
    }
  else if (initial_meta_theme_set && !initial_theme_saved)
    {
      add_custom_row_to_meta_theme (initial_meta_theme_info.gtk_theme_name,
				    initial_meta_theme_info.metacity_theme_name,
				    initial_meta_theme_info.icon_theme_name,
				    FALSE);
    }
  else
    {
      remove_custom_row_from_meta_theme ();
    }
  g_free (current_gtk_theme);
  g_free (current_window_theme);
  g_free (current_icon_theme);
  update_settings_from_gconf_idle_id = 0;
  return FALSE;
}

void
update_settings_from_gconf (void)
{
  if (update_settings_from_gconf_idle_id != 0)
    return;
  update_settings_from_gconf_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
							update_settings_from_gconf_idle,
							NULL, NULL);
}

static void
gtk_theme_key_changed (GConfClient *client,
		       guint        cnxn_id,
		       GConfEntry  *entry,
		       gpointer     user_data)
{
  if (strcmp (entry->key, GTK_THEME_KEY))
    return;

  update_settings_from_gconf ();
  gnome_theme_details_update_from_gconf ();
}

static void
window_settings_changed (GnomeWindowManager *window_manager,
			 GladeXML           *dialog)
{
  static gchar *window_theme = NULL;
  GnomeWMSettings wm_settings;

  wm_settings.flags = GNOME_WM_SETTING_THEME;
  gnome_window_manager_get_settings (window_manager, &wm_settings);
  if (window_theme == NULL || strcmp (wm_settings.theme, window_theme) != 0)
    {
      g_free (window_theme);
      window_theme = g_strdup (wm_settings.theme);
    }
  else
    return;

  update_settings_from_gconf ();
  gnome_theme_details_update_from_gconf ();
}

static void
update_font_button_state (GladeXML *dialog)
{
  GConfClient *client = gconf_client_get_default ();
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  GtkTreeIter iter;
  
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("meta_theme_treeview")));
  
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      GnomeThemeMetaInfo *meta_theme_info;
      char *meta_theme_name, *str;
      
      gtk_tree_model_get (model, &iter,
			  META_THEME_ID_COLUMN, &meta_theme_name,
			  -1);
      if (!meta_theme_name)
	return;
      
      meta_theme_info = gnome_theme_meta_info_find (meta_theme_name);

      g_assert (meta_theme_info);
      g_free (meta_theme_name);

      str = gconf_client_get_string (client, FONT_KEY, NULL);
      
      if (meta_theme_info->application_font != NULL && str != NULL &&
	  strcmp (meta_theme_info->application_font, str) == 0)
	{
	  gtk_widget_set_sensitive (WID ("meta_theme_font1_button"), FALSE);
	  gtk_widget_set_sensitive (WID ("meta_theme_font2_button"), FALSE);
	}
      else
	{
	  gtk_widget_set_sensitive (WID ("meta_theme_font1_button"), TRUE);
	  gtk_widget_set_sensitive (WID ("meta_theme_font2_button"), TRUE);
	}

      g_free (str);
    }  
  g_object_unref (client);  
}

static void
font_key_changed (GConfClient        *client,
		  guint               cnxn_id,
		  GConfEntry         *entry,
		  gpointer            user_data)
{
  GladeXML *dialog = user_data;

  update_font_button_state (dialog);
}

static void
icon_key_changed (GConfClient *client,
		  guint        cnxn_id,
		  GConfEntry  *entry,
		  gpointer     user_data)
{
  if (strcmp (entry->key, ICON_THEME_KEY))
    return;

  update_settings_from_gconf ();
  gnome_theme_details_update_from_gconf ();
}

static gboolean
theme_changed_idle (gpointer data)
{
  GladeXML *dialog;
  dialog = gnome_theme_manager_get_theme_dialog ();

  update_themes_from_disk (dialog);
  gnome_theme_details_reread_themes_from_disk ();
  gtk_widget_grab_focus (WID ("meta_theme_treeview"));
  theme_changed_idle_id = 0;
  return FALSE;
}

/* FIXME: We want a more sophisticated theme_changed func sometime */
static void
theme_changed_func (gpointer uri,
		    gpointer user_data)
{
  if (theme_changed_idle_id != 0)
    return;
  theme_changed_idle_id =
    g_idle_add_full (G_PRIORITY_HIGH_IDLE,
		     theme_changed_idle,
		     NULL, NULL);
}

static void
cb_dialog_response (GtkDialog *dialog, gint response_id)
{
  if (response_id == GTK_RESPONSE_HELP)
    capplet_help (GTK_WINDOW (dialog), "user-guide.xml", "goscustdesk-12");
  else
    gtk_main_quit ();
}

static void
setup_meta_tree_view (GtkTreeView *tree_view,
		      GCallback    changed_callback,
		      GladeXML    *dialog)
{
  GtkTreeModel *model;
  GtkTreeSelection *selection;
  GtkCellRenderer *renderer;

  renderer = g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF,
			   "xpad", 4,
			   "ypad", 4,
			   NULL);

  gtk_tree_view_insert_column_with_attributes (tree_view,
 					       -1, NULL,
 					       renderer,
 					       "pixbuf", META_THEME_PIXBUF_COLUMN,
 					       NULL);
  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (tree_view,
 					       -1, NULL,
 					       renderer,
 					       "markup", META_THEME_NAME_COLUMN,
 					       NULL);

  model = (GtkTreeModel *) gtk_list_store_new (META_N_COLUMNS,
					       G_TYPE_STRING,    /* META_THEME_NAME_COLUMN   */
					       G_TYPE_STRING,    /* META_THEME_ID_COLUMN     */
					       G_TYPE_UINT,      /* META_THEME_FLAG_COLUMN   */
					       GDK_TYPE_PIXBUF); /* META_THEME_PIXBUF_COLUMN */
  gtk_tree_view_set_model (tree_view, model);
  selection = gtk_tree_view_get_selection (tree_view);
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
  g_signal_connect (G_OBJECT (selection), "changed", changed_callback, dialog);
}


static void
gnome_meta_theme_installer_run_cb (GtkWidget *button,
				   GtkWidget *parent_window)
{
  gnome_theme_installer_run (parent_window, NULL);
}


static void
gnome_theme_save_clicked (GtkWidget *button,
			  gpointer   data)
{
  GladeXML *dialog;

  dialog = gnome_theme_manager_get_theme_dialog ();

  gnome_theme_save_show_dialog (WID ("theme_dialog"), &custom_meta_theme_info);
}

static void
apply_font_clicked (GtkWidget *button,
		    gpointer   data)
{
  GladeXML *dialog = data;
  GConfClient *client;
  GtkTreeSelection *selection;
  GtkTreeModel *model;
  GtkTreeIter iter;
  
  client = gconf_client_get_default ();
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("meta_theme_treeview")));
  
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      GnomeThemeMetaInfo *meta_theme_info;
      char *meta_theme_name;
      
      gtk_tree_model_get (model, &iter,
			  META_THEME_ID_COLUMN, &meta_theme_name,
			  -1);
      meta_theme_info = gnome_theme_meta_info_find (meta_theme_name);

      g_assert (meta_theme_info);
      g_free (meta_theme_name);

      gconf_client_set_string (client, FONT_KEY, meta_theme_info->application_font, NULL);
    }  
  g_object_unref (client);
}

static void
revert_theme_clicked (GtkWidget *button,
						gpointer data)
{
  GladeXML *dialog;

  gnome_meta_theme_set(&initial_meta_theme_info);
  
  dialog = gnome_theme_manager_get_theme_dialog ();
  gtk_widget_set_sensitive(WID("meta_theme_revert_button"), FALSE);  
  reverted = TRUE;
}
	
static void
setup_dialog (GladeXML *dialog)
{
  GConfClient *client;
  GtkWidget *parent, *widget;
  GnomeWindowManager *window_manager;
  GtkSizeGroup *size_group;

  default_image = gdk_pixbuf_new_from_file(GNOMECC_DATA_DIR "/pixmaps/theme-thumbnailing.png", NULL);
  broken_image = gdk_pixbuf_new_from_file(GNOMECC_DATA_DIR "/pixmaps/theme-thumbnailing.png", NULL);

  client = gconf_client_get_default ();

  window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ()));
  
  parent = WID ("theme_dialog");

  size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
  gtk_size_group_add_widget (size_group, WID ("meta_theme_details_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_install_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_save_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_font1_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_background1_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_font2_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_background2_button"));
  gtk_size_group_add_widget (size_group, WID ("meta_theme_revert_button"));
  g_object_unref (size_group);

  gtk_widget_set_sensitive(WID("meta_theme_revert_button"),FALSE);

  g_signal_connect (G_OBJECT (WID ("meta_theme_install_button")), "clicked", G_CALLBACK (gnome_meta_theme_installer_run_cb), parent);

  g_signal_connect (G_OBJECT (WID ("meta_theme_details_button")), "clicked", gnome_theme_details_show, NULL);

  g_signal_connect (G_OBJECT (WID ("meta_theme_font1_button")), "clicked", G_CALLBACK (apply_font_clicked), dialog);

  g_signal_connect (G_OBJECT (WID ("meta_theme_revert_button")), "clicked", G_CALLBACK (revert_theme_clicked),NULL);

  setup_meta_tree_view (GTK_TREE_VIEW (WID ("meta_theme_treeview")),
			(GCallback) meta_theme_selection_changed,
			dialog);

  gconf_client_add_dir (client, "/desktop/gnome/interface", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);

  gconf_client_notify_add (client,
			   GTK_THEME_KEY,
			   (GConfClientNotifyFunc) &gtk_theme_key_changed,
			   dialog, NULL, NULL);
  gconf_client_notify_add (client,
			   ICON_THEME_KEY,
			   (GConfClientNotifyFunc) &icon_key_changed,
			   dialog, NULL, NULL);

  gconf_client_notify_add (client,
			   FONT_KEY,
			   (GConfClientNotifyFunc) &font_key_changed,
			   dialog, NULL, NULL);
  g_object_unref (client);

  if (window_manager)
    g_signal_connect (G_OBJECT (window_manager),
		      "settings_changed",
		      (GCallback) window_settings_changed, dialog);

  update_themes_from_disk (dialog);
  gtk_widget_grab_focus (WID ("meta_theme_treeview"));
  gnome_theme_info_register_theme_change (theme_changed_func, dialog);



  widget = WID ("meta_theme_save_button");
  g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (gnome_theme_save_clicked), NULL);


/*
  g_signal_connect (G_OBJECT (WID ("install_dialog")), "response",
		    G_CALLBACK (install_dialog_response), dialog);
  */

  g_signal_connect (G_OBJECT (parent), "response", G_CALLBACK (cb_dialog_response), NULL);

  gtk_drag_dest_set (parent, GTK_DEST_DEFAULT_ALL,
		     drop_types, n_drop_types,
		     GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE);
  g_signal_connect (G_OBJECT (parent), "drag-motion", G_CALLBACK (gnome_theme_manager_drag_motion_cb), NULL);
  g_signal_connect (G_OBJECT (parent), "drag-leave", G_CALLBACK (gnome_theme_manager_drag_leave_cb), NULL);
  g_signal_connect (G_OBJECT (parent), "drag-data-received",G_CALLBACK (gnome_theme_manager_drag_data_received_cb), NULL);

  capplet_set_icon (parent, "gnome-settings-theme");

  update_font_button_state (dialog);
  gtk_widget_show (parent);

}

/* Non static functions */
GladeXML *
gnome_theme_manager_get_theme_dialog (void)
{
  static GladeXML *dialog = NULL;

  if (dialog == NULL)
    dialog = glade_xml_new (GLADEDIR "/theme-properties.glade", NULL, NULL);

  return dialog;
}

gint
gnome_theme_manager_sort_func (const gchar *a_str,
			       const gchar *b_str,
			       guint        a_flag,
			       guint        b_flag)
{
  gint retval;
  gint agreater = FALSE, bgreater = FALSE;

  if (a_flag & THEME_FLAG_CUSTOM)
    agreater = TRUE;
  if (b_flag & THEME_FLAG_CUSTOM)
    bgreater = TRUE;

  if (agreater && !bgreater)
    return -1;
  if (!agreater && bgreater)
    return 1;

  if (a_flag & THEME_FLAG_DEFAULT)
    agreater = TRUE;
  if (b_flag & THEME_FLAG_DEFAULT)
    bgreater = TRUE;

  if (agreater && !bgreater)
    return -1;
  if (!agreater && bgreater)
    return 1;

  retval = g_utf8_collate (a_str?a_str:"",
			   b_str?b_str:"");

  return retval;
}

/* Starts nautilus on the themes directory*/
void
gnome_theme_manager_show_manage_themes (GtkWidget *button, gpointer data)
{
	gchar *path, *command;
	GnomeVFSURI *uri;

	path = g_strdup_printf ("%s/.themes", g_get_home_dir ());
	uri = gnome_vfs_uri_new (path);

	if (!gnome_vfs_uri_exists (uri)) {
		/* Create the directory */
		gnome_vfs_make_directory_for_uri (uri, 0775);
	}
	gnome_vfs_uri_unref (uri);

	command = g_strdup_printf ("nautilus --no-desktop %s", path);
	g_free (path);

	g_spawn_command_line_async (command, NULL);
	g_free (command);
}

/* Starts nautilus on the icon themes directory*/
void
gnome_theme_manager_icon_show_manage_themes (GtkWidget *button, gpointer data)
{
	gchar *path, *command;
	GnomeVFSURI *uri;

	path = g_strdup_printf ("%s/.icons", g_get_home_dir ());
	uri = gnome_vfs_uri_new (path);

	if (!gnome_vfs_uri_exists (uri)) {
		/* Create the directory */
		gnome_vfs_make_directory_for_uri (uri, 0775);
	}
	gnome_vfs_uri_unref (uri);

	command = g_strdup_printf ("nautilus --no-desktop %s", path);
	g_free (path);

	g_spawn_command_line_async (command, NULL);
	g_free (command);
}

/* Show the nautilus themes window */
void
gnome_theme_manager_window_show_manage_themes (GtkWidget *button, gpointer data)
{
	gchar *path, *command;
	GnomeVFSURI *uri;
	GnomeWindowManager *wm;

	wm = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ()));

	path = gnome_window_manager_get_user_theme_folder (wm);
	g_object_unref (G_OBJECT (wm));

	uri = gnome_vfs_uri_new (path);

	if (!gnome_vfs_uri_exists (uri)) {
		/* Create the directory */
		gnome_vfs_make_directory_for_uri (uri, 0775);
	}
	gnome_vfs_uri_unref (uri);


	command = g_strdup_printf ("nautilus --no-desktop %s", path);
	g_free (path);

	g_spawn_command_line_async (command, NULL);
	g_free (command);
}

/* Callback issued during drag movements */
gboolean
gnome_theme_manager_drag_motion_cb (GtkWidget *widget, GdkDragContext *context,
				    gint x, gint y, guint time, gpointer data)
{
	return FALSE;
}

/* Callback issued during drag leaves */
void
gnome_theme_manager_drag_leave_cb (GtkWidget *widget, GdkDragContext *context,
	       guint time, gpointer data)
{
	gtk_widget_queue_draw (widget);
}

/* Callback issued on actual drops. Attempts to load the file dropped. */
void
gnome_theme_manager_drag_data_received_cb (GtkWidget *widget, GdkDragContext *context,
					   gint x, gint y,
					   GtkSelectionData *selection_data,
					   guint info, guint time, gpointer data)
{
	GList *uris;
	gchar *filename = NULL;

	if (!(info == TARGET_URI_LIST || info == TARGET_NS_URL))
		return;

	uris = gnome_vfs_uri_list_parse ((gchar *) selection_data->data);
	if (uris != NULL && uris->data != NULL) {
		GnomeVFSURI *uri = (GnomeVFSURI *) uris->data;

		if (gnome_vfs_uri_is_local (uri))
			filename = gnome_vfs_unescape_string (
					gnome_vfs_uri_get_path (uri),
					G_DIR_SEPARATOR_S);
		else
			filename = gnome_vfs_unescape_string (
					gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE),
					G_DIR_SEPARATOR_S);

		gnome_vfs_uri_list_unref (uris);
	}

	gnome_theme_installer_run (widget, filename);
	g_free (filename);
}


static gchar *
get_default_string_from_key (const char *key)
{
  GConfClient *client;
  GConfValue *value;
  GError *error = NULL;
  gchar *str = NULL;

  client = gconf_client_get_default ();
  value = gconf_client_get_default_from_schema (client, key, &error);
  g_object_unref (client);

  if (error)
    {
      g_clear_error (&error);
      return NULL;
    }

  if (value)
    {
      if (value->type == GCONF_VALUE_STRING)
	str = gconf_value_to_string (value);
      gconf_value_free (value);
    }

  return str;
}

int
main (int argc, char *argv[])
{
  GladeXML *dialog;

  /* We need to do this before we initialize anything else */
  theme_thumbnail_factory_init (argc, argv);

  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);

  gnome_program_init ("gnome-theme-manager", VERSION,
		      LIBGNOMEUI_MODULE, argc, argv,
		      GNOME_PARAM_APP_DATADIR, GNOMECC_DATA_DIR,
		      NULL);

  gtk_theme_default_name = get_default_string_from_key (GTK_THEME_KEY);
  window_theme_default_name = get_default_string_from_key (METACITY_THEME_KEY);
  icon_theme_default_name = get_default_string_from_key (ICON_THEME_KEY);

  if (gtk_theme_default_name == NULL ||
      window_theme_default_name == NULL ||
      icon_theme_default_name == NULL)
    {
      GtkWidget *msg_dialog;

      msg_dialog = gtk_message_dialog_new (NULL,
				       GTK_DIALOG_MODAL,
				       GTK_MESSAGE_ERROR,
				       GTK_BUTTONS_OK,
				       _("The default theme schemas could not be found on your system.  This means that you probably don't have metacity installed, or that your gconf is configured incorrectly."));
      gtk_dialog_run (GTK_DIALOG (msg_dialog));
      gtk_widget_destroy (msg_dialog);
      exit (0);
    }

  gnome_theme_init (NULL);

  gnome_wm_manager_init ();
  activate_settings_daemon ();

  dialog = gnome_theme_manager_get_theme_dialog ();

  setup_dialog (dialog);

  gtk_main ();

  return 0;
}
