/*
    Copyright (C) 2008-2010 Stefan Haller

    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 3 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, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <libintl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include "../misc/general.h"
#include "../misc/xml.h"
#include "../misc/module.h"
#include "desktopnova-profiles.h"
#include "../modules/desktopnova_module.h"

#include "../misc/authors.h"
#include "../misc/license.h"
#include "../misc/translators.h"

#define _(message) dgettext(GETTEXT_PACKAGE, message)

GPtrArray * modules;

/* main window */
GtkWidget * mainwindow;
GtkWidget * notebook;
GtkWidget * vbox_all;
GtkWidget * vbox_images;
GtkWidget * vbox_settings;
GtkWidget * vbox_modules;
GtkWidget * vbox_tray;
GtkWidget * vbox_advanced;
GtkWidget * label_images;
GtkWidget * hbox_profiles;
GtkWidget * label_profiles;
GtkWidget * combo_profiles;
GtkWidget * button_edit;
GtkWidget * hbox_images;
GtkWidget * scrolled_tree_images;
GtkWidget * tree_images;
GtkWidget * vbox_buttons;
GtkWidget * button_add;
GtkWidget * button_add_folder;
GtkWidget * button_remove;
GtkWidget * button_clear;
GtkWidget * label_settings;
GtkWidget * vbox_time;
GtkWidget * checkbox_interval;
GtkWidget * alignment_interval;
GtkWidget * hbox_interval;
GtkWidget * label_interval;
GtkWidget * spinbutton_interval;
GtkWidget * checkbox_every_start;
GtkWidget * hbox_daemon;
GtkWidget * button_start;
GtkWidget * button_stop;
GtkWidget * checkbox_autostart;
GtkWidget * checkbox_autostart_tray;
#ifdef CACHE_FILE_LIST
GtkWidget * checkbox_cache;
#endif
GtkWidget * label_modules;
GtkWidget * button_modules;
GtkWidget * button_about;
GtkWidget * label_tray_unavailable;
GtkWidget * checkbox_mouse_wheel;
GtkWidget * label_filter;
GtkWidget * entry_filter;
GtkWidget * button_filter_reset;
GtkWidget * button_save;

GtkListStore * list_images;
GtkCellRenderer * renderer_type;
GtkCellRenderer * renderer_filename;
GtkCellRenderer * renderer_subfolders;
GtkTreeViewColumn * column_type;
GtkTreeViewColumn * column_filename;
GtkTreeViewColumn * column_subfolders;

GtkListStore * list_profiles;
GtkCellRenderer * renderer_name;
/* **** */

/* module window */
GtkWidget * window_modules;
GtkWidget * vbox_wmodules;
GtkWidget * buttonbox_wmodules;
GtkWidget * scrolled_wmodules_tree;
GtkWidget * tree_wmodules_modules;
GtkWidget * expander_wmodules;
GtkWidget * label_wmodules_module;
GtkWidget * text_wmodules_module_description;
GtkWidget * label_wmodules_module_author;
GtkWidget * label_wmodules_module_homepage;
GtkWidget * label_wmodules_module_filename;
GtkWidget * button_wmodules_ok;
GtkWidget * button_wmodules_cancel;

GtkListStore * list_wmodules_modules;
GtkCellRenderer * render_wmodules_active;
GtkCellRenderer * render_wmodules_name;
GtkTreeViewColumn * column_wmodules_active;
GtkTreeViewColumn * column_wmodules_name;
/* **** */

gboolean settings_changed = FALSE;

enum
{
	COLUMN_IMAGE_TYPE,
	COLUMN_IMAGE_FILE,
	COLUMN_IMAGE_SUBFOLDERS,
	N_IMAGE_COLUMNS
};


enum
{
	COLUMN_PROFILE_NAME,
	COLUMN_PROFILE_STORE,
	N_PROFILE_COLUMNS
};

enum
{
	COLUMN_WMODULES_ACTIVE,
	COLUMN_WMODULES_NAME,
	COLUMN_WMODULES_MODULE,
	N_WMODULES_COLUMNS
};

gboolean check_autorun()
{
	gboolean result = FALSE;

	gchar * filename = g_build_filename(g_get_user_config_dir(), "autostart",
	                                    AUTORUNFILE, NULL);
	struct stat buf;
	result = ! stat(filename, &buf);
	g_free(filename);

	return result;
}

gboolean check_autorun_tray()
{
	gboolean result = FALSE;

	gchar * filename = g_build_filename(g_get_user_config_dir(), "autostart",
	                                    AUTORUNTRAYFILE, NULL);
	struct stat buf;
	result = ! stat(filename, &buf);
	g_free(filename);

	return result;
}

gboolean check_tray()
{
	gboolean result = FALSE;

	gchar * filename = g_build_filename(BINDIR, "desktopnova-tray", NULL);

	struct stat buf;
	result = ! stat(filename, &buf);
	g_free(filename);

	return result;
}

void read_modules()
{
	GDir * dir = g_dir_open(PKGLIBDIR, 0, NULL);
	if (dir != NULL)
	{
		const gchar * fname;
		while ((fname = g_dir_read_name (dir)) != NULL)
		{
			guint length = strlen(fname);
			if (length > 10)
			{
				/* check name, maybe this should be done a bit better ;) */
				if ((fname[0] == 'm') &&
				    (fname[1] == 'o') &&
				    (fname[2] == 'd') &&
				    (fname[3] == 'u') &&
				    (fname[4] == 'l') &&
				    (fname[5] == 'e') &&
				    (fname[6] == '_') &&
				    (fname[length-3] == '.') &&
				    (fname[length-2] == 's') &&
				    (fname[length-1] == 'o'))
				{
					gchar * abs_fname = g_build_filename(PKGLIBDIR,
					                                     fname, NULL);
					struct library_entry * lib_ent = load_module(abs_fname);
					if (lib_ent != NULL)
					{
						lib_ent->filename = g_strdup(fname);
						g_ptr_array_add(modules, lib_ent);
					}
					g_free(abs_fname);
				}
			}
		}
		g_dir_close(dir);
	}
}

void set_autorun(gboolean autorun, gboolean autorun_tray)
{
	gint i;
	gboolean tmp;
	gchar * content;
	gchar * filename;

	gchar * autorun_dir = g_build_filename(g_get_user_config_dir(), "autostart", NULL);
	GDir * dir = g_dir_open(autorun_dir, 0, NULL);
	if (dir == NULL)
	{
		if (g_mkdir_with_parents(autorun_dir, S_IRUSR | S_IWUSR | S_IXUSR |
			S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
		{
			GtkWidget * dialog = gtk_message_dialog_new(NULL,
			                                            GTK_DIALOG_MODAL,
			                                            GTK_MESSAGE_ERROR,
			                                            GTK_BUTTONS_OK,
			                                            _("Failed to create " \
			                                              "directory \"%s\"."),
			                                            autorun_dir);
			gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
			                                         _("Error: %s\n\nThe " \
			                                           "application will " \
			                                           "be terminated."),
			                                         g_strerror(errno));
			gtk_dialog_run(GTK_DIALOG(dialog));
			gtk_widget_destroy(dialog);
		}
	}
	else
	{
		g_dir_close(dir);

		for (i = 0; i < 2; i++)
		{
			switch (i)
			{
				case 0:
					filename = g_build_filename(g_get_user_config_dir(), "autostart",
					                            AUTORUNFILE, NULL);
					content = AUTORUNCONTENT;
					tmp = autorun;
					break;
				case 1:
					filename = g_build_filename(g_get_user_config_dir(), "autostart",
					                            AUTORUNTRAYFILE, NULL);
					content = AUTORUNTRAYCONTENT;
					tmp = autorun_tray;
					break;
			}

			if (tmp)
			{
				g_file_set_contents(filename, content, -1, NULL);
			}
			else
			{
				remove(filename);
			}
			g_free(filename);
		}
	}
	g_free(autorun_dir);
}

void check_app_dir()
{
	gchar * app_dir = get_app_dir();
	if (app_dir == NULL)
	{
		GtkWidget * dialog = gtk_message_dialog_new(NULL,
		                                            GTK_DIALOG_MODAL,
		                                            GTK_MESSAGE_ERROR,
		                                            GTK_BUTTONS_OK,
		                                            _("Couldn't get user " \
		                                              "config directory!"));
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		                                         _("Error: %s\n\nThe " \
		                                           "application will be " \
		                                           "terminated."),
		                                         g_strerror(errno));
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);	
		exit(1);
	}

	GDir * dir = g_dir_open(app_dir, 0, NULL);
	if (dir == NULL)
	{
		if (g_mkdir_with_parents(app_dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP
		    | S_IXGRP | S_IROTH| S_IXOTH) == -1)
		{
			GtkWidget * dialog = gtk_message_dialog_new(NULL,
			                                            GTK_DIALOG_MODAL,
			                                            GTK_MESSAGE_ERROR,
			                                            GTK_BUTTONS_OK,
			                                            _("Failed to create " \
			                                              "directory \"%s\"."),
			                                            app_dir);
			gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
			                                         _("Error: %s\n\nThe " \
			                                           "application will be " \
			                                           "terminated."),
			                                         g_strerror(errno));
			gtk_dialog_run(GTK_DIALOG(dialog));
			gtk_widget_destroy(dialog);	
			exit(1);
		}
	}
	else
	{
		g_dir_close(dir);
	}

	g_free(app_dir);
}

void eval_system_call(int result)
{
	if ((result == -1) || (result == 127))
	{
		gchar * error = 0;
		gchar * error2 = 0;
		if (result == -1)
		{
			error = _("system() returned error-code (-1)!");
			error2 = g_strdup_printf(_("Error: %s"), g_strerror(errno));
		}
		else
		{
			error = _("system() returned error-code (127)!");
			error2 = _("Error: /bin/sh could not be executed.");
		}
		GtkWidget * dialog = gtk_message_dialog_new(NULL,
		                                            GTK_DIALOG_MODAL,
		                                            GTK_MESSAGE_ERROR,
		                                            GTK_BUTTONS_OK,
		                                            "%s",
		                                            error);
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		                                         "%s",
		                                         error2);
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);	
	}
}

/* parsing */

void load()
{
	struct profile_node * profile;
	struct file_node * file;
	struct module_node * module;
	struct settings * set = load_settings();
	GtkTreeIter iter, olditer;
	GtkListStore * store;
	gchar * oldprofile = NULL;

	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_interval), TRUE);
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_interval), FALSE);
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_interval),
	                            set->changebyinterval);
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_every_start),
	                            set->changeeverylaunch);
	#ifdef CACHE_FILE_LIST
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_cache),
	                            set->cachefilelist);
	#endif
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_mouse_wheel),
	                            set->mouse_wheel);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_interval), set->interval);

	profile = set->profiles;
	if (profile == NULL)
	{
		/* MEMLEAK */
		/* no profile to load; create default profile */
		store = gtk_list_store_new(N_IMAGE_COLUMNS, G_TYPE_BOOLEAN,
		                           G_TYPE_STRING, G_TYPE_BOOLEAN);
		gtk_list_store_append(list_profiles, &iter);
		gtk_list_store_set(list_profiles, &iter,
		                   COLUMN_PROFILE_NAME, _("default"),
		                   COLUMN_PROFILE_STORE, store,
		                   -1);
		gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_profiles), &iter);
	}

	while (profile != NULL)	
	{
		/* MEMLEAK */
		store = gtk_list_store_new(N_IMAGE_COLUMNS, G_TYPE_BOOLEAN,
		                           G_TYPE_STRING, G_TYPE_BOOLEAN);

		/* sort profile names at startup */
		if (oldprofile == NULL)
		{
			gtk_list_store_append(list_profiles, &iter);
		}
		else
		{
			if (g_strcmp0(profile->name, oldprofile))
			{
				gtk_list_store_insert_after(list_profiles,
				                             &iter,
				                             &olditer);
			}
			else
			{
				gtk_list_store_insert_before(list_profiles,
				                            &iter,
				                            &olditer);
			}
		}
		olditer = iter;

		gtk_list_store_set(list_profiles, &iter,
		                   COLUMN_PROFILE_NAME, profile->name,
		                   COLUMN_PROFILE_STORE, store,
		                   -1);

		/* set default profile */
		if (g_strcmp0(profile->name, set->default_profile) == 0)
		{
			gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_profiles), &iter);
		}

		file = profile->files;
		while (file != NULL)
		{
			gtk_list_store_append(store, &iter);
			gtk_list_store_set(store, &iter,
			                   COLUMN_IMAGE_TYPE, file->is_dir,
			                   COLUMN_IMAGE_FILE, file->filename,
			                   COLUMN_IMAGE_SUBFOLDERS, file->use_subfolders,
			                   -1);
			file = file->next;
		}

		oldprofile = profile->name;
		profile = profile->next;
	}

	module = set->modules;
	while (module != NULL)	
	{
		guint i;
		for (i = 0; i < modules->len; i++)
		{
			struct library_entry * lib =
			       (struct library_entry *)g_ptr_array_index(modules, i);

			const gchar * mod_name = lib->filename;
			if (g_strcmp0(mod_name, module->name) == 0)
			{
				lib->active = TRUE;
			}
		}

		module = module->next;
	}

	gchar * filters = set->filters;
	if (filters == NULL)
	{
		filters = "";
	}
	if (g_strcmp0(filters, "") == 0)
	{
		filters = DEFAULT_FILTERS;
	}
	gtk_entry_set_text(GTK_ENTRY(entry_filter), filters);

	free_settings(set);
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_autostart),
	                            check_autorun());
	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_autostart_tray),
	                            check_autorun_tray());

	gboolean has_tray = check_tray();
	if (! has_tray)
	{
		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_autostart_tray),
		                            FALSE);
		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(checkbox_mouse_wheel),
		                            FALSE);
	}
	gtk_widget_set_sensitive(checkbox_mouse_wheel, has_tray);
	gtk_widget_set_sensitive(checkbox_autostart_tray, has_tray);

	if (has_tray)
	{
		gtk_widget_hide(label_tray_unavailable);
	}
	else
	{
		gtk_widget_show(label_tray_unavailable);
	}
}

void iter_to_file_node(GtkListStore * store, GtkTreeIter * iter,
                       struct file_node * node)
{
	// init GValue
	GValue value = {0, };

	node->next = NULL;

	// is_dir
	gtk_tree_model_get_value(GTK_TREE_MODEL(store), iter, COLUMN_IMAGE_TYPE,
	                         &value);
	node->is_dir = g_value_get_boolean(&value);
	g_value_unset(&value);

	// filename
	gtk_tree_model_get_value(GTK_TREE_MODEL(store), iter, COLUMN_IMAGE_FILE,
	                         &value);
	node->filename = g_strdup(g_value_get_string(&value));
	g_value_unset(&value);

	// use_subfolders
	gtk_tree_model_get_value(GTK_TREE_MODEL(store), iter,
	                         COLUMN_IMAGE_SUBFOLDERS, &value);
	node->use_subfolders = g_value_get_boolean(&value);
	g_value_unset(&value);
}

void iter_to_profile_node(GtkTreeIter * iter, struct profile_node * profile)
{
	GtkListStore * store;
	GtkTreeIter iter_pic;
	struct file_node * file;
	GValue value = {0, };

	profile->next = NULL;
	profile->files = NULL;

	// name
	gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), iter,
	                         COLUMN_PROFILE_NAME, &value);
	profile->name = g_strdup(g_value_get_string(&value));
	g_value_unset(&value);

	// store
	gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), iter,
	                         COLUMN_PROFILE_STORE, &value);
	store = (GtkListStore *) g_value_get_pointer(&value);
	g_value_unset(&value);

	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter_pic))
	{
		file = g_new(struct file_node, 1);
		profile->files = file;

		iter_to_file_node(store, &iter_pic, file);

		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter_pic))
		{
			file->next = g_new(struct file_node, 1);
			file = file->next;

			iter_to_file_node(store, &iter_pic, file);
		}
	}
}

gboolean save()
{
	guint i;
	gboolean module_active = FALSE;
	for (i = 0; i < modules->len; i++)
	{
		struct library_entry * lib =
		       (struct library_entry *)g_ptr_array_index(modules, i);
		if (lib->active)
		{
			module_active = TRUE;
			break;
		}
	}

	if (! module_active)
	{
		GtkWidget * dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow),
		                                           GTK_DIALOG_MODAL,
		                                           GTK_MESSAGE_WARNING,
		                                           GTK_BUTTONS_YES_NO,
		                                           _("No module is active!"));
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		                                         _("At least one module " \
		                                           "should be active, " \
		                                           "otherwise the daemon " \
		                                           "can't change the " \
		                                           "desktop wallpaper.\n\n"
		                                           "Save anyway?"));
		if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
		{
			module_active = TRUE;
		}
		gtk_widget_destroy(dialog);
	}

	if (! module_active)
	{
		return FALSE;
	}

	struct settings * set = g_new(struct settings, 1);
	set->changebyinterval = gtk_toggle_button_get_active(
	                        GTK_TOGGLE_BUTTON(checkbox_interval));
	set->interval = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinbutton_interval));
	set->changeeverylaunch = gtk_toggle_button_get_active(
	                         GTK_TOGGLE_BUTTON(checkbox_every_start));
	#ifdef CACHE_FILE_LIST
	set->cachefilelist = gtk_toggle_button_get_active(
	                     GTK_TOGGLE_BUTTON(checkbox_cache));
	#endif
	set->mouse_wheel = gtk_toggle_button_get_active(
	                   GTK_TOGGLE_BUTTON(checkbox_mouse_wheel));
	set->profiles = NULL;
	set->modules = NULL;
	set->default_profile = NULL;
	set->filters = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry_filter)));

	struct module_node * last_module = NULL;
	for (i = 0; i < modules->len; i++)
	{
		struct library_entry * lib =
		       (struct library_entry *)g_ptr_array_index(modules, i);
		if (lib->active)
		{
			struct module_node * module = g_new(struct module_node, 1);
			module->next = NULL;

			const gchar * name = lib->filename;
			module->name = g_strdup(name);

			if (last_module == NULL)
			{
				set->modules = module;
				last_module = module;
			}
			else
			{
				last_module->next = module;
				last_module = module;
			}
		}
	}

	GtkTreeIter iter;
	GValue value = {0, };
	struct profile_node * profile;

	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo_profiles), &iter))
	{
		gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), &iter,
		                         COLUMN_PROFILE_NAME, &value);
		set->default_profile = g_strdup(g_value_get_string(&value));
		g_value_unset(&value);
	}

	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_profiles), &iter))
	{
		profile = g_new(struct profile_node, 1);
		set->profiles = profile;

		iter_to_profile_node(&iter, profile);

		while (gtk_tree_model_iter_next(GTK_TREE_MODEL(list_profiles), &iter))
		{
			profile->next = g_new(struct profile_node, 1);
			profile = profile->next;

			iter_to_profile_node(&iter, profile);
		}
	}
	save_settings(set);

	#ifdef CACHE_FILE_LIST
	if (!set->cachefilelist)
	{
		/* remove cache file */
		gchar * app_dir = get_app_dir();
		gchar * filename = g_build_filename(app_dir, CACHEFILE, NULL);
		remove(filename);
		g_free(filename);
		g_free(app_dir);
	}
	#endif
	free_settings(set);

	set_autorun(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox_autostart)),
	            gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox_autostart_tray)));

	/* send daemon SIGHUP -> reload settings and images */
	eval_system_call(system("/usr/bin/killall -s SIGHUP desktopnova-daemon 2> /dev/null"));

	settings_changed = FALSE;

	return TRUE;
}

void callback_settings_changed(struct ProfileSettings * settings)
{
	GtkTreeIter iter;
	struct ProfileItem * item;
	GValue value = {0, };
	gpointer selected_entry;
	gboolean has_selection_changed = FALSE;
	GtkListStore * store;
	unsigned int i;

	/* get selected entry */
	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo_profiles), &iter))
	{
		gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), &iter,
		                         COLUMN_PROFILE_STORE, &value);
		selected_entry = g_value_get_pointer(&value);
		g_value_unset(&value);
	}

	/* create a array with all pointer to a GtkListStore */
	GArray * old_stores = g_array_new(FALSE, FALSE, sizeof(GtkListStore *));
	gboolean result = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_profiles),
	                                                &iter);
	while (result)
	{
		gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), &iter,
		                         COLUMN_PROFILE_STORE, &value);
		store = g_value_get_pointer(&value);
		g_value_unset(&value);

		g_array_append_val(old_stores, store);

		result = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_profiles),
		                                  &iter);
	}

	/* clear old list */
	gtk_list_store_clear(list_profiles);

	/* fill list */
	item = settings->profile_items;
	if (item == NULL)
	{
		/* no profile; create default profile */
		store = gtk_list_store_new(N_IMAGE_COLUMNS, G_TYPE_BOOLEAN,
		                           G_TYPE_STRING, G_TYPE_BOOLEAN);
		gtk_list_store_append(list_profiles, &iter);
		gtk_list_store_set(list_profiles, &iter,
				COLUMN_PROFILE_NAME, _("default"),
				COLUMN_PROFILE_STORE, store,
				-1);
	}

	while (item != NULL)
	{
		if (item->store == NULL)
		{
			item->store = gtk_list_store_new(N_IMAGE_COLUMNS, G_TYPE_BOOLEAN,
			                                 G_TYPE_STRING, G_TYPE_BOOLEAN);
		}
		else
		{
			/* search the pointer in the array and remove it */
			for (i = 0; i < old_stores->len; i++)
			{
				if (item->store == g_array_index(old_stores, GtkListStore *, i))
				{
					g_array_remove_index_fast(old_stores, i);
					break;
				}
			}
		}
		gtk_list_store_append(list_profiles, &iter);
		gtk_list_store_set(list_profiles, &iter,
				COLUMN_PROFILE_NAME, item->name,
				COLUMN_PROFILE_STORE, item->store,
				-1);

		if (item->store == selected_entry)
		{
			gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_profiles), &iter);
			has_selection_changed = TRUE;
		}

		item = item->next;
	}

	/* all unused pointer are in the array now */
	for (i = 0; i < old_stores->len; i++)
	{
		g_object_unref(g_array_index(old_stores, /*GtkListStore*/ GObject *, i));
	}

	if (! has_selection_changed)
	{
		gtk_combo_box_set_active (GTK_COMBO_BOX(combo_profiles), 0);
	}

	g_array_free(old_stores, TRUE);

	settings_changed = TRUE;
}

/* GUI and event-handling */

void render_wmodules_active_toggled (GtkCellRendererToggle * cell_renderer,
                                     gchar * pathStr, gpointer user_data) 
{
	GtkTreeIter iter;
	GValue value = {0};

	// get TreeIteer
	GtkTreePath * path = gtk_tree_path_new_from_string(pathStr);
	gtk_tree_model_get_iter(GTK_TREE_MODEL(list_wmodules_modules), &iter, path);
	gtk_tree_path_free(path);

	gtk_tree_model_get_value(GTK_TREE_MODEL(list_wmodules_modules), &iter,
	                         COLUMN_WMODULES_ACTIVE, &value);
	g_value_set_boolean(&value, ! g_value_get_boolean(&value));
	gtk_list_store_set_value(GTK_LIST_STORE(list_wmodules_modules), &iter,
	                         COLUMN_WMODULES_ACTIVE, &value);

	g_value_unset(&value);
}

void tree_wmodules_modules_cursor_changed(GtkTreeView * tree, gpointer user_data)
{
	GtkTreePath * path;
	GtkTreeIter iter;
	gtk_tree_view_get_cursor(GTK_TREE_VIEW(tree_wmodules_modules), &path, NULL);
	if (path != NULL)
	{
		gtk_tree_model_get_iter(GTK_TREE_MODEL(list_wmodules_modules), &iter, path);

		GValue value = {0, };

		gtk_tree_model_get_value(GTK_TREE_MODEL(list_wmodules_modules), &iter,
		                         COLUMN_WMODULES_MODULE, &value);
		struct library_entry * lib = g_value_get_pointer(&value);
		g_value_unset(&value);

		gchar * tmp = g_markup_escape_text((*lib->name)(), -1);
		gchar * module = g_strdup_printf("<big><b>%s</b> %s</big>", tmp,
		                                 (*lib->version)());
		g_free(tmp);

		tmp = g_markup_escape_text((*lib->author)(), -1);
		gchar * author = g_strdup_printf(_("<b>Author:</b> %s"), tmp);
		g_free(tmp);

		tmp = g_markup_escape_text((*lib->homepage)(), -1);
		gchar * homepage = g_strdup_printf(_("<b>Homepage:</b> %s"), tmp);
		g_free(tmp);

		tmp = g_markup_escape_text(lib->filename, -1);
		gchar * filename = g_strdup_printf(_("<b>Filename:</b> %s/%s"), PKGLIBDIR, tmp);
		g_free(tmp);

		gtk_label_set_markup(GTK_LABEL(label_wmodules_module), module);
		gtk_label_set_markup(GTK_LABEL(label_wmodules_module_author), author);
		gtk_label_set_markup(GTK_LABEL(label_wmodules_module_homepage), homepage);
		gtk_label_set_markup(GTK_LABEL(label_wmodules_module_filename), filename);

		GtkTextBuffer * buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (text_wmodules_module_description));
		gtk_text_buffer_set_text(buffer, (*lib->description)(), -1);

		g_free(module);
		g_free(author);
		g_free(homepage);
		g_free(filename);
		gtk_tree_path_free(path);
	}
}

void button_wmodules_cancel_clicked(GtkButton * button, gpointer user_data)
{
	gtk_widget_destroy(window_modules);
}

void button_wmodules_ok_clicked(GtkButton * button, gpointer user_data)
{
	GtkTreeIter iter;
	struct library_entry * lib = NULL;

	gboolean result = gtk_tree_model_get_iter_first(
	                  GTK_TREE_MODEL(list_wmodules_modules),
	                  &iter);
	while (result)
	{
		GValue value = {0, };

		gtk_tree_model_get_value(GTK_TREE_MODEL(list_wmodules_modules), &iter,
		                         COLUMN_WMODULES_MODULE, &value);
		lib = g_value_get_pointer(&value);
		g_value_unset(&value);

		gtk_tree_model_get_value(GTK_TREE_MODEL(list_wmodules_modules), &iter,
		                         COLUMN_WMODULES_ACTIVE, &value);
		lib->active = g_value_get_boolean(&value);
		g_value_unset(&value);

		result = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_wmodules_modules),
		                                  &iter);
	}

	settings_changed = TRUE;

	gtk_widget_destroy(window_modules);
}

void create_module_window()
{
	/* create widgets */
	window_modules = g_object_new(GTK_TYPE_WINDOW,
	                             "title", _("Modules"),
	                             "default-width", 350,
	                             "default-height", 300,
	                             "resizable", TRUE,
	                             "window-position", GTK_WIN_POS_CENTER,
	                             "border-width", 12,
	                             "modal", TRUE,
	                             NULL);

	vbox_wmodules = gtk_vbox_new(FALSE, 12);
	scrolled_wmodules_tree = gtk_scrolled_window_new(NULL, NULL);
	list_wmodules_modules = gtk_list_store_new(N_WMODULES_COLUMNS,
	                                           G_TYPE_BOOLEAN,
	                                           G_TYPE_STRING,
	                                           G_TYPE_POINTER);

	tree_wmodules_modules = gtk_tree_view_new_with_model(
	                        GTK_TREE_MODEL(list_wmodules_modules));
	g_object_unref(G_OBJECT(list_wmodules_modules));

	buttonbox_wmodules = g_object_new(GTK_TYPE_HBUTTON_BOX,
	                                  "layout-style", GTK_BUTTONBOX_END,
	                                  "spacing", 12,
	                                  NULL);

	button_wmodules_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
	button_wmodules_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);

	render_wmodules_active = gtk_cell_renderer_toggle_new();
	render_wmodules_name = gtk_cell_renderer_text_new();

	column_wmodules_active = gtk_tree_view_column_new_with_attributes(_("Active"),
	                                                    render_wmodules_active,
	                                                    "active",
	                                                    COLUMN_WMODULES_ACTIVE,
	                                                    NULL);
	column_wmodules_name = gtk_tree_view_column_new_with_attributes (_("Name"),
	             render_wmodules_name, "markup", COLUMN_WMODULES_NAME, NULL);

	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_wmodules_modules),
	                            column_wmodules_active);

	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_wmodules_modules),
	                            column_wmodules_name);
	expander_wmodules = gtk_expander_new(_("Details"));

	label_wmodules_module = g_object_new(GTK_TYPE_LABEL,
	                                     "label", _("No item selected"),
	                                     "xalign", 0.0f,
	                                     "yalign", 0.5f,
	                                     "selectable", TRUE,
	                                     NULL);
	label_wmodules_module_author = g_object_new(GTK_TYPE_LABEL,
	                                     "label", _("No item selected"),
	                                     "xalign", 0.0f,
	                                     "yalign", 0.5f,
	                                     "selectable", TRUE,
	                                     "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
	                                     NULL);
	label_wmodules_module_homepage = g_object_new(GTK_TYPE_LABEL,
	                                     "label", _("No item selected"),
	                                     "xalign", 0.0f,
	                                     "yalign", 0.5f,
	                                     "selectable", TRUE,
	                                     "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
	                                     NULL);

	label_wmodules_module_filename = g_object_new(GTK_TYPE_LABEL,
	                                     "label", _("No item selected"),
	                                     "xalign", 0.0f,
	                                     "yalign", 0.5f,
	                                     "selectable", TRUE,
	                                     "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
	                                     NULL);

	text_wmodules_module_description = gtk_text_view_new ();	

	GtkWidget * hseparator = gtk_hseparator_new();
	GtkWidget * vbox_details = gtk_vbox_new(FALSE, 3);


	/* set up widgets */
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_wmodules_tree),
	                               GTK_POLICY_AUTOMATIC,  GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_wmodules_tree),
	                                    GTK_SHADOW_ETCHED_IN);
	gtk_text_view_set_editable(GTK_TEXT_VIEW(text_wmodules_module_description),
	                           FALSE);
	gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text_wmodules_module_description),
	                                 FALSE);
	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_wmodules_module_description),
	                            GTK_WRAP_WORD);

	/* packing controls */
	gtk_container_add(GTK_CONTAINER(scrolled_wmodules_tree), tree_wmodules_modules);
	gtk_container_add(GTK_CONTAINER(expander_wmodules), vbox_details);

	gtk_box_pack_start(GTK_BOX(vbox_wmodules), scrolled_wmodules_tree, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_wmodules), hseparator, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_wmodules), expander_wmodules, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_wmodules), buttonbox_wmodules, FALSE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(buttonbox_wmodules), button_wmodules_cancel, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(buttonbox_wmodules), button_wmodules_ok, FALSE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(vbox_details), label_wmodules_module, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_details), text_wmodules_module_description, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_details), label_wmodules_module_author, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_details), label_wmodules_module_homepage, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_details), label_wmodules_module_filename, FALSE, FALSE, 0);

	gtk_container_add(GTK_CONTAINER(window_modules), vbox_wmodules);

	/* connect signals */
	g_signal_connect(G_OBJECT(render_wmodules_active), "toggled",
	                 G_CALLBACK(render_wmodules_active_toggled), 0);

	g_signal_connect(G_OBJECT(tree_wmodules_modules), "cursor-changed",
	                 G_CALLBACK(tree_wmodules_modules_cursor_changed), 0);

	g_signal_connect(G_OBJECT(button_wmodules_ok), "clicked",
	                 G_CALLBACK(button_wmodules_ok_clicked), 0);

	g_signal_connect(G_OBJECT(button_wmodules_cancel), "clicked",
	                 G_CALLBACK(button_wmodules_cancel_clicked), 0);


	/* add modules to list */
	guint i;
	for (i = 0; i < modules->len; i++)
	{
		GtkTreeIter iter;

		struct library_entry * lib = (struct library_entry *)g_ptr_array_index(modules, i);

		gboolean active = lib->active;
		gchar * name = g_strdup_printf("<b>%s</b> %s", (*lib->name)(),
		                               (*lib->version)());
		gtk_list_store_append(GTK_LIST_STORE(list_wmodules_modules), &iter);
		gtk_list_store_set(GTK_LIST_STORE(list_wmodules_modules), &iter,
		                   COLUMN_WMODULES_ACTIVE, active,
		                   COLUMN_WMODULES_NAME, name,
		                   COLUMN_WMODULES_MODULE, lib,
		                   -1);
		g_free(name);
	}


	gtk_widget_show_all(window_modules);
}

void destroy(GtkWidget *widget, gpointer data)
{
	gtk_main_quit();
}

gboolean delete(GtkWidget *widget, gpointer data)
{
	/* other event handlers should work and destroy the window */
	gboolean result = FALSE;

	if (settings_changed)
	{
		GtkWidget * dialog = gtk_message_dialog_new(NULL,
		                                            GTK_DIALOG_MODAL,
		                                            GTK_MESSAGE_QUESTION,
		                                            GTK_BUTTONS_YES_NO,
		                                            _("Save changes?"));

		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		                                        _("Saved changes in settings " \
		                                          "will be loaded by the " \
		                                          "daemon automatically."));
		gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);

		if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
		{
			result = !save();
		}
		gtk_widget_destroy (dialog);
	}

	return result;
}

void combo_profiles_changed(GtkWidget * widget, gpointer user_data)
{
	GtkTreeIter iter;
	GValue value = {0, };
	GtkListStore * store;

	/* get new list_store and set it */
	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo_profiles), &iter))
	{
		gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), &iter,
		                         COLUMN_PROFILE_STORE, &value);
		store = (GtkListStore *)g_value_get_pointer(&value);
		g_value_unset(&value);

		list_images = store;
		gtk_tree_view_set_model(GTK_TREE_VIEW(tree_images),
		                        GTK_TREE_MODEL(store));

		/* don't use g_object_unref(..) with the store! */
	}

	settings_changed = TRUE;
}

void button_edit_clicked(GtkButton * button, gpointer user_data)
{
	struct ProfileSettings profile_settings;
	GtkTreeIter iter;
	GValue value = {0, };
	struct ProfileItem * item = NULL;

	profile_settings.succeed = TRUE;
	profile_settings.profile_items = NULL;

	gboolean result = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_profiles),
	                                                &iter);
	while (result)
	{
		if (item == NULL)
		{
			profile_settings.profile_items = g_new(struct ProfileItem, 1);
			item =  profile_settings.profile_items;
		}
		else
		{
			item->next = g_new(struct ProfileItem, 1);
			item = item->next;
		}

		item->next = NULL;

		gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), &iter,
		                         COLUMN_PROFILE_NAME, &value);
		item->name = g_strdup(g_value_get_string(&value));
		g_value_unset(&value);

		gtk_tree_model_get_value(GTK_TREE_MODEL(list_profiles), &iter,
		                         COLUMN_PROFILE_STORE, &value);
		item->store = g_value_get_pointer(&value);
		g_value_unset(&value);

		result = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_profiles), &iter);
	}

	show_profile_settings(&profile_settings);
	free_profile_settings(&profile_settings);
}

void button_add_clicked(GtkButton * button, gpointer user_data)
{
	gchar * filename;
	GtkTreeIter iter;

	GtkWidget * dialog = gtk_file_chooser_dialog_new(_("Select File"),
	                                               GTK_WINDOW(mainwindow),
	                                               GTK_FILE_CHOOSER_ACTION_OPEN,
	                                               GTK_STOCK_CANCEL,
	                                               GTK_RESPONSE_CANCEL,
	                                               GTK_STOCK_OPEN,
	                                               GTK_RESPONSE_ACCEPT,
	                                               NULL);

	GtkFileFilter * filter_all = gtk_file_filter_new();
	gtk_file_filter_set_name(filter_all, _("All files"));
	gtk_file_filter_add_pattern(filter_all, "*");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),filter_all);

	GtkFileFilter * filter_images = gtk_file_filter_new();
	gtk_file_filter_set_name(filter_images, _("All images"));
	gtk_file_filter_add_mime_type(filter_images, "image/*");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),filter_images);

	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
	{
		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));

		gtk_list_store_append(list_images, &iter);
		gtk_list_store_set(list_images, &iter,
		                   COLUMN_IMAGE_TYPE, FALSE,
		                   COLUMN_IMAGE_FILE, filename,
		                   COLUMN_IMAGE_SUBFOLDERS, FALSE,
		                   -1);

		g_free(filename);
		settings_changed = TRUE;
	}

	gtk_widget_destroy (dialog);
}

void button_add_folder_clicked(GtkButton * button, gpointer user_data)
{
	char * filename;
	GtkTreeIter iter;

	GtkWidget * dialog = gtk_file_chooser_dialog_new(_("Select Folder"),
	                                      GTK_WINDOW(mainwindow),
	                                      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
	                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
	                                      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
	                                      NULL);

	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
	{
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));

		gtk_list_store_append(list_images, &iter);
		gtk_list_store_set(list_images, &iter,
		                   COLUMN_IMAGE_TYPE, TRUE,
		                   COLUMN_IMAGE_FILE, filename,
		                   COLUMN_IMAGE_SUBFOLDERS, TRUE,
		                   -1);


		g_free(filename);
		settings_changed = TRUE;
	}

	gtk_widget_destroy (dialog);
}

void button_remove_clicked(GtkButton * button, gpointer user_data)
{
	GtkTreePath * path;
	GtkTreeIter iter;
	gtk_tree_view_get_cursor(GTK_TREE_VIEW(tree_images), &path, NULL);
	if (path != NULL)
	{
		gtk_tree_model_get_iter(GTK_TREE_MODEL(list_images), &iter, path);

		gtk_list_store_remove(list_images, &iter);
		settings_changed = TRUE;
	}
}

void button_clear_clicked(GtkButton * button, gpointer user_data)
{
	gtk_list_store_clear(list_images);
	settings_changed = TRUE;
}

void button_about_clicked(GtkButton * button, gpointer user_data)
{
	const gchar * authors[2] = {AUTHORS, NULL};
	gtk_show_about_dialog(NULL,
	                "program-name", "DesktopNova",
	                "logo", gtk_window_get_icon(GTK_WINDOW(mainwindow)),
	                "title", _("About DesktopNova"),
	                "version", VERSION,
	                "copyright", "Stefan Haller 2008-2010",
	                "authors", authors,
	                "license", LICENSE,
	                "translator-credits", TRANSLATORS,
	                "website", "https://launchpad.net/desktopnova",
	                "comments", _("DesktopNova changes your wallpaper in a " \
	                              "given time interval"),
	                NULL);
}

void button_save_clicked(GtkButton * button, gpointer user_data)
{
	save();
}

void button_start_clicked(GtkButton * button, gpointer user_data)
{
	gboolean result;
	if (settings_changed)
	{
		GtkWidget * dialog = gtk_message_dialog_new(NULL,
		                                            GTK_DIALOG_MODAL,
		                                            GTK_MESSAGE_QUESTION,
		                                            GTK_BUTTONS_YES_NO,
		                                            _("Save changes?"));

		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		                                         _("If you don't save the " \
		                                           "changes, the daemon will" \
		                                           " load the old settings!"));
		gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);

		if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
		{
			result = save();
		}
		gtk_widget_destroy (dialog);
	}

	if (result)
		eval_system_call(system(BINDIR "/desktopnova-daemon &"));
}

void button_stop_clicked(GtkButton * button, gpointer user_data)
{
	eval_system_call(system("/usr/bin/killall desktopnova-daemon 2> /dev/null"));
}

void button_pidlock_clicked(GtkButton * button, gpointer user_data)
{
	gchar * app_dir = get_app_dir();
	gchar * filename = g_build_filename(app_dir, PIDLOCKFILE, NULL);
	g_free(app_dir);
	if (remove(filename) == -1)
	{
		gchar * message = "";
		if (errno == ENOENT)
		{
			/* TRANSLATORS: pid is a shorthand for "process identifier" 
			    see http://en.wikipedia.org/wiki/Process_identifier     */
			message = _("\n\n(This doesn't indicate an error. " \
			            "The pid-lock file doesn't exist, so " \
			            "it can't prevent the start of the " \
			            "daemon.)");
		}

		gchar * secondary = g_strdup_printf(_("Error: %s%s"), g_strerror(errno),
		                                                      message);

		GtkWidget * dialog = gtk_message_dialog_new(NULL,
		                                            GTK_DIALOG_MODAL,
		                                            GTK_MESSAGE_ERROR,
		                                            GTK_BUTTONS_OK,
		                                            /* TRANSLATORS: pid is a shorthand for "process identifier" 
		                                               see http://en.wikipedia.org/wiki/Process_identifier      */
		                                            _("Failed to remove " \
		                                              "pid-lock file " \
		                                              "\"%s\"."),
		                                            filename);
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
		                                         "%s",
		                                         secondary);
		g_free(secondary);
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);
	}
	g_free(filename);
}

void button_modules_clicked(GtkButton * button, gpointer user_data)
{
	create_module_window();
}

void checkbox_interval_toggled(GtkToggleButton * togglebutton,
                               gpointer user_data)
{
	gboolean enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton));
	gtk_widget_set_sensitive(label_interval, enabled);
	gtk_widget_set_sensitive(spinbutton_interval, enabled);
	settings_changed = TRUE;
}

void checkbox_toggled(GtkToggleButton * togglebutton,
                      gpointer user_data)
{
	settings_changed = TRUE;
}

void spinbutton_interval_changed (GtkEntry * togglebutton, gpointer user_data)
{
	settings_changed = TRUE;
}

void button_filter_reset_clicked(GtkButton * button, gpointer user_data)
{
	gtk_entry_set_text(GTK_ENTRY(entry_filter), DEFAULT_FILTERS);
}

void  render_subfolders_toggled (GtkCellRendererToggle * cell_renderer,
                                 gchar * pathStr, gpointer user_data) 
{
	GtkTreeIter iter;
	GValue value = {0};

	// get TreeIteer
	GtkTreePath * path = gtk_tree_path_new_from_string(pathStr);
	gtk_tree_model_get_iter(GTK_TREE_MODEL(list_images), &iter, path);

	//check if it is a directory
	gtk_tree_model_get_value(GTK_TREE_MODEL(list_images), &iter,
	                         COLUMN_IMAGE_TYPE, &value);
	if (g_value_get_boolean(&value))
	{
		g_value_unset(&value);

		gtk_tree_model_get_value(GTK_TREE_MODEL(list_images), &iter,
		                         COLUMN_IMAGE_SUBFOLDERS, &value);
		g_value_set_boolean(&value, ! g_value_get_boolean(&value));
		gtk_list_store_set_value(GTK_LIST_STORE(list_images), &iter,
		                         COLUMN_IMAGE_SUBFOLDERS, &value);

		g_value_unset(&value);
		settings_changed = TRUE;
	}
	else
	{
		g_value_unset(&value);
	}
}

void create_and_show_mainwindow()
{
	/* create all controls */
	mainwindow = g_object_new(GTK_TYPE_WINDOW,
	                            "title", _("DesktopNova"),
	                            "default-width", 450,
	                            "default-height", 400,
	                            "resizable", TRUE,
	                            "window-position", GTK_WIN_POS_CENTER,
	                            "border-width", 12,
	                            NULL);
	vbox_all = gtk_vbox_new(FALSE, 12);
	vbox_images = gtk_vbox_new(FALSE, 12);
	vbox_settings = gtk_vbox_new(FALSE, 12);
	vbox_modules = gtk_vbox_new(FALSE, 12);
	vbox_tray = gtk_vbox_new(FALSE, 12);
	vbox_advanced = gtk_vbox_new(FALSE, 12);

	GtkWidget * hbox_filter = gtk_hbox_new(FALSE, 8);

	GtkWidget * align;

	notebook = gtk_notebook_new();
	gtk_notebook_set_homogeneous_tabs(GTK_NOTEBOOK(notebook), TRUE);

	#define NEW_ALIGN(x) align = gtk_alignment_new(0.5, 0.5, 1, 1); \
	                     gtk_alignment_set_padding(GTK_ALIGNMENT(align), \
	                                               12, 12, 12, 12); \
	                     gtk_container_add(GTK_CONTAINER(align), x);

	NEW_ALIGN(vbox_images);

	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
	                         align,
	                         gtk_label_new(_("Images")));

	NEW_ALIGN(vbox_settings);

	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
	                         align,
	                         gtk_label_new(_("Settings")));

	NEW_ALIGN(vbox_tray);

	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
	                         align,
	                         gtk_label_new(_("Tray-Icon")));

	NEW_ALIGN(vbox_advanced);

	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
	                         align,
	                         gtk_label_new(_("Advanced")));

	#undef NEW_ALIGN

	label_images = g_object_new(GTK_TYPE_LABEL,
	                              "label", _("<b>Images:</b>"),
	                              "use-markup", TRUE,
	                              "xalign", 0.0f,
	                              "yalign", 0.5f,
	                              NULL);

	label_settings = g_object_new(GTK_TYPE_LABEL,
	                              "label", _("<b>Settings:</b>"),
	                              "use-markup", TRUE,
	                              "xalign", 0.0f,
	                              "yalign", 0.5f,
	                              NULL);

	label_modules = g_object_new(GTK_TYPE_LABEL,
	                              "label", _("<b>Modules:</b>"),
	                              "use-markup", TRUE,
	                              "xalign", 0.0f,
	                              "yalign", 0.5f,
	                              NULL);
	label_profiles = gtk_label_new(_("Profile:"));

	hbox_profiles = gtk_hbox_new(FALSE,6);

	list_profiles = gtk_list_store_new(N_PROFILE_COLUMNS,
	                                   G_TYPE_STRING,
	                                   G_TYPE_POINTER);

	combo_profiles = g_object_new(GTK_TYPE_COMBO_BOX,
	                              "model", GTK_TREE_MODEL(list_profiles),
	                              "tooltip-text", _("Select the profile, " \
	                                                "which you would like to " \
	                                                "activate or change."),
	                              NULL);
	g_object_unref(G_OBJECT(list_profiles));
	renderer_name = gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_profiles),
	                           renderer_name, TRUE);
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_profiles),
	                               renderer_name, "text",
	                               COLUMN_PROFILE_NAME, NULL);
	hbox_images = gtk_hbox_new(FALSE,6);
	list_images = NULL;
	scrolled_tree_images = gtk_scrolled_window_new(NULL, NULL);
	tree_images = gtk_tree_view_new();
	renderer_filename = gtk_cell_renderer_text_new();
	renderer_type = gtk_cell_renderer_toggle_new();
	renderer_subfolders = gtk_cell_renderer_toggle_new();
	column_type = gtk_tree_view_column_new_with_attributes(_("Folder"),
	                                                       renderer_type,
	                                                       "active",
	                                                       COLUMN_IMAGE_TYPE,
	                                                       NULL);
	column_filename = gtk_tree_view_column_new_with_attributes(_("Filename"),
	                                                        renderer_filename,
	                                                        "text",
	                                                        COLUMN_IMAGE_FILE,
	                                                        NULL);
	column_subfolders = gtk_tree_view_column_new_with_attributes(
	                                                 _("Subfolders"),
	                                                 renderer_subfolders,
	                                                 "active",
	                                                 COLUMN_IMAGE_SUBFOLDERS,
	                                                 NULL);

	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_images), column_type);
	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_images), column_filename);
	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_images), column_subfolders);

	vbox_buttons = gtk_vbox_new(FALSE,6);
	button_edit = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Edit"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_EDIT,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Edit the name of the " \
	                                            "profiles."),
	                          NULL);
	button_add = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Add"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_ADD,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Add a single file to the " \
	                                            "list."),
	                          NULL);
	button_add_folder = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Add Folder"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_ADD,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Add a folder to the list."),
	                          NULL);
	button_remove = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Remove"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_REMOVE,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Remove the selected item."),
	                          NULL);
	button_clear = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Remove All"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_CLEAR,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Remove all items from the " \
	                                            "list."),
	                          NULL);
	button_start = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Start Daemon"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_CONNECT,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Start the daemon. The " \
	                                            "daemon works in the " \
	                                            "background and changes the " \
	                                            "wallpaper."),
	                          NULL);
	button_stop = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Stop Daemon"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_DISCONNECT,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Stop the daemon. The daemon " \
	                                            "works in the background and " \
	                                            "changes the wallpaper."),
	                          NULL);
	button_save = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Save settings"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_SAVE,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Save settings and restart " \
	                                            "the daemon."),
	                          NULL);
	button_modules = g_object_new(GTK_TYPE_BUTTON,
	                          "label", _("Modules"),
	                          "image", gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,
	                                   GTK_ICON_SIZE_BUTTON),
	                          "tooltip-text", _("Select different modules. " \
	                                          "The daemon uses the moules to " \
	                                          "change the wallpaper."),
	                          NULL);

	checkbox_interval = g_object_new(GTK_TYPE_CHECK_BUTTON,
	                                 "label", _("Change wallpaper in " \
	                                            "intervals"),
	                                 "tooltip-text", _("Change the wallpaper " \
	                                                   "automatically after " \
	                                                   "a given time."),
	                                 NULL);
	checkbox_every_start = g_object_new(GTK_TYPE_CHECK_BUTTON,
	                                 "label", _("Change wallpaper every launch"),
	                                 "tooltip-text", _("Change the wallpaper " \
	                                                   "when the daemon " \
	                                                   "starts."),
	                                 NULL);
	#ifdef CACHE_FILE_LIST
	checkbox_cache = g_object_new(GTK_TYPE_CHECK_BUTTON,
	                                 "label", _("Cache file list " \
	                                            "(EXPERIMENTAL)"),
	                                 "tooltip-text", _("Save the list of " \
	                                                   "all wallpapers into " \
	                                                   "a cache file. This " \
	                                                   "option needs more " \
	                                                   "RAM, but the daemon " \
	                                                   "can start more " \
	                                                   "quickly.\n\nThis " \
	                                                   "Feature is only " \
	                                                   "experimental!"),
	                                 NULL);
	#endif
	checkbox_autostart = g_object_new(GTK_TYPE_CHECK_BUTTON,
	                                 "label", _("Launch daemon every session " \
	                                            "(Autorun)"),
	                                 "tooltip-text", _("Starts the daemon " \
	                                                   "automatically when " \
	                                                   "you log in."),
	                                 NULL);
	checkbox_autostart_tray = g_object_new(GTK_TYPE_CHECK_BUTTON,
	                                 "label", _("Launch tray-icon every session " \
	                                            "(Autorun)"),
	                                 "tooltip-text", _("Starts the tray-icon " \
	                                                   "automatically when " \
	                                                   "you log in."),
	                                 NULL);
	checkbox_mouse_wheel = g_object_new(GTK_TYPE_CHECK_BUTTON,
	                                 "label", _("Enable mouse wheel switching"),
	                                 "tooltip-text", _("Change the wallpaper " \
	                                                   "by using the mouse " \
	                                                   "wheel."),
	                                 NULL);
	label_tray_unavailable = g_object_new(GTK_TYPE_LABEL,
	                                      "label", _("<span foreground=\"red\">" \
	                                                 "The tray icon is not " \
	                                                 "installed. If you want " \
	                                                 "to use the tray icon, " \
	                                                 "you have to install it " \
	                                                 "first!</span>"),
	                                      "wrap", TRUE,
	                                      "justify", GTK_JUSTIFY_CENTER,
	                                      "use-markup", TRUE,
	                                      NULL);
	label_filter = g_object_new(GTK_TYPE_LABEL,
	                            "label", _("File extension filter:"),
	                            "xalign", 0.0f,
	                            "yalign", 0.5f,
	                            NULL);
	entry_filter = g_object_new(GTK_TYPE_ENTRY,
	                            "tooltip-text", _("Only files which extension " \
	                                              "is one of the specified " \
	                                              "will be used by the " \
	                                              "daemon. Separate " \
	                                              "file extensions by a " \
	                                              "single space character."),
	                            NULL);
	button_filter_reset = g_object_new(GTK_TYPE_BUTTON,
	                                   "label", GTK_STOCK_CLEAR,
	                                   "use-stock", TRUE,
	                                   "tooltip-text", _("Reset file " \
	                                                     "extension filter"),
	                                   NULL);

	vbox_time = gtk_vbox_new(FALSE, 6);
	alignment_interval = gtk_alignment_new(1.0f, 0.5f, 0.9f, 1.0f);
	hbox_interval = gtk_hbox_new(0, 12);
	label_interval = gtk_label_new(_("Interval (in minutes):"));
	spinbutton_interval = gtk_spin_button_new_with_range(1, G_MAXINT, 1);
	hbox_daemon = gtk_hbox_new(TRUE, 0);
	button_about = gtk_button_new_from_stock(GTK_STOCK_ABOUT);

	/* set attributes */
	gtk_window_set_icon_from_file(GTK_WINDOW(mainwindow),
	                              DATADIR "/icons/hicolor/scalable/apps/" \
	                                      "desktopnova.svg", 0);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_tree_images),
	                               GTK_POLICY_AUTOMATIC,
	                               GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_tree_images),
	                                    GTK_SHADOW_ETCHED_IN);

	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column_filename), TRUE);

	/* packing all controls */
	gtk_box_pack_start(GTK_BOX(vbox_all), notebook, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_all), button_save, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_all), button_about, FALSE, FALSE, 0);

	gtk_container_add (GTK_CONTAINER (scrolled_tree_images), tree_images); 
	gtk_box_pack_start(GTK_BOX(vbox_images), label_images, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_images), hbox_profiles, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_images), hbox_images, TRUE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(hbox_images), scrolled_tree_images, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox_images), vbox_buttons, FALSE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(hbox_profiles), label_profiles, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox_profiles), combo_profiles, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox_profiles), button_edit, FALSE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(vbox_buttons), button_add, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_buttons), button_add_folder, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_buttons), button_remove, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_buttons), button_clear, FALSE, FALSE, 0);

	gtk_box_pack_start(GTK_BOX(vbox_settings), label_settings, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_settings), vbox_time, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_settings), hbox_daemon, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_settings), checkbox_autostart, FALSE, TRUE, 0);
	#ifdef CACHE_FILE_LIST
	gtk_box_pack_start(GTK_BOX(vbox_settings), checkbox_cache, FALSE, TRUE, 0);
	#endif
	gtk_box_pack_start(GTK_BOX(vbox_settings), label_modules, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_settings), button_modules, FALSE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(vbox_time), checkbox_interval, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_time), alignment_interval, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_time), checkbox_every_start, TRUE, TRUE, 0);

	gtk_container_add(GTK_CONTAINER(alignment_interval), hbox_interval);
	gtk_box_pack_start(GTK_BOX(hbox_interval), label_interval, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox_interval), spinbutton_interval, TRUE, TRUE, 0);	

	gtk_box_pack_start(GTK_BOX(hbox_daemon), button_start, TRUE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox_daemon), button_stop, TRUE, FALSE, 0);

	gtk_box_pack_start(GTK_BOX(vbox_tray), label_tray_unavailable, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_tray), checkbox_autostart_tray, FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_tray), checkbox_mouse_wheel, FALSE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(vbox_advanced), label_filter, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox_advanced), hbox_filter, FALSE, FALSE, 0);

	gtk_box_pack_start(GTK_BOX(hbox_filter), entry_filter, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox_filter), button_filter_reset, FALSE, FALSE, 0);

	gtk_container_add(GTK_CONTAINER(mainwindow), vbox_all);

	/* connect signals */	
	g_signal_connect(G_OBJECT(mainwindow), "destroy",
	                 G_CALLBACK(destroy), 0);

	g_signal_connect(G_OBJECT(mainwindow), "delete-event",
	                 G_CALLBACK(delete), 0);

	g_signal_connect(G_OBJECT(button_edit), "clicked",
	                 G_CALLBACK(button_edit_clicked), 0);

	g_signal_connect(G_OBJECT(combo_profiles), "changed",
	                 G_CALLBACK(combo_profiles_changed), 0);

	g_signal_connect(G_OBJECT(button_add), "clicked",
	                 G_CALLBACK(button_add_clicked), 0);

	g_signal_connect(G_OBJECT(button_add_folder), "clicked",
	                 G_CALLBACK(button_add_folder_clicked), 0);

	g_signal_connect(G_OBJECT(button_remove), "clicked",
	                 G_CALLBACK(button_remove_clicked), 0);

	g_signal_connect(G_OBJECT(button_clear), "clicked",
	                 G_CALLBACK(button_clear_clicked), 0);

	g_signal_connect(G_OBJECT(button_about), "clicked",
	                 G_CALLBACK(button_about_clicked), 0);

	g_signal_connect(G_OBJECT(button_start), "clicked",
	                 G_CALLBACK(button_start_clicked), 0);

	g_signal_connect(G_OBJECT(button_stop), "clicked",
	                 G_CALLBACK(button_stop_clicked), 0);

	g_signal_connect(G_OBJECT(renderer_subfolders), "toggled",
	                 G_CALLBACK(render_subfolders_toggled), 0);

	g_signal_connect(G_OBJECT(checkbox_interval), "toggled",
	                 G_CALLBACK(checkbox_interval_toggled), 0);

	g_signal_connect(G_OBJECT(checkbox_every_start), "toggled",
	                 G_CALLBACK(checkbox_toggled), 0);

	g_signal_connect(G_OBJECT(checkbox_autostart), "toggled",
	                 G_CALLBACK(checkbox_toggled), 0);

	g_signal_connect(G_OBJECT(checkbox_autostart_tray), "toggled",
	                 G_CALLBACK(checkbox_toggled), 0);

	g_signal_connect(G_OBJECT(checkbox_mouse_wheel), "toggled",
	                 G_CALLBACK(checkbox_toggled), 0);

	#ifdef CACHE_FILE_LIST
	g_signal_connect(G_OBJECT(checkbox_cache), "toggled",
	                 G_CALLBACK(checkbox_toggled), 0);
	#endif

	g_signal_connect(G_OBJECT(spinbutton_interval), "value-changed",
	                 G_CALLBACK(spinbutton_interval_changed), 0);

	g_signal_connect(G_OBJECT(button_filter_reset), "clicked",
	                 G_CALLBACK(button_filter_reset_clicked), 0);

	g_signal_connect(G_OBJECT(button_modules), "clicked",
	                 G_CALLBACK(button_modules_clicked), 0);

	g_signal_connect(G_OBJECT(button_save), "clicked",
	                 G_CALLBACK(button_save_clicked), 0);

	/* display all controls */
	gtk_widget_show_all(mainwindow);
}

int main (int argc, char *argv[])
{
	/* Initialize i18n support */
	gtk_set_locale();
	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
	/* Initialize the widget set */

	gtk_init (&argc, &argv);

	/* Maybe the app dir doesn't exist, so we must create it. */
	check_app_dir();

	modules = g_ptr_array_new();
	read_modules();

	create_and_show_mainwindow();

	/* load settings */
	load();

	/* Maybe load_xml sent a signal to controls and settings_changed changed. */
	settings_changed = FALSE;

	/* Enter the main event loop, and wait for user interaction */
	gtk_main ();

	/* free used modules */
	guint i;
	for (i = 0; i < modules->len; i++)
	{
		struct library_entry * lib = (struct library_entry *)
		                             g_ptr_array_index(modules, i);
		/* mustn't be unloaded, because we use gconf (and glib) with static 
		   variables in the module! */
		//dlclose(lib->lib);
		g_free(lib->filename);
		g_free(lib);
	}
	g_ptr_array_free(modules, TRUE);

	return 0;
}

#undef _
