Logo Search packages:      
Sourcecode: galeon version File versions

galeon-prefs-dialog.c

/*
 *  Copyright (C) 2003  Tommi Komulainen
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation. 
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "galeon-prefs-dialog.h"
#include "galeon-prefs-dialog-data.h"

#include "eel-gconf-extensions.h"
#include "galeon-embed-prefs.h"
#include "galeon-embed-shell.h"
#include "galeon-language-editor.h"
#include "galeon-marshal.h"
#include "gul-general.h"
#include "gul-glade.h"
#include "gul-glade-gconf.h"
#include "gul-gui-option.h"
#include "gul-gui.h"
#include "gul-state.h"
#include "gul-iso-codes.h"
#include "pixbuf-cache.h"
#include "prefs-strings.h"
#include "hig-alert.h"

#include <glib/gi18n.h>
#include <gtk/gtkcelllayout.h>
#include <gtk/gtkcellrendererpixbuf.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkcombobox.h>
#include <gtk/gtkcomboboxentry.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkiconfactory.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtkmain.h>
#include <gtk/gtknotebook.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtkstock.h>
#include <gtk/gtktreemodelsort.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtklabel.h>

#include <string.h>

/* name of the proxy configuration program */
#ifndef GNOME_NETWORK_PREFERENCES
#define GNOME_NETWORK_PREFERENCES       "gnome-network-preferences"
#endif

/* delay (ms) before applying changes in font size spinbuttons */
#define FONTS_SPIN_TIMEOUT    500

/* gul-state keys for saving state */
#define STATE_FONTS_ENCODING "Preferences/fonts_encoding"

/* stock items */
#define GALEON_STOCK_PREFS_GENERAL     "galeon-prefs-general"
#define GALEON_STOCK_PREFS_LANGUAGE    "galeon-prefs-language"
#define GALEON_STOCK_PREFS_FONTS       "galeon-prefs-fonts"
#define GALEON_STOCK_PREFS_TABS        "galeon-prefs-tabs"
#define GALEON_STOCK_PREFS_MOUSE       "galeon-prefs-mouse"
#define GALEON_STOCK_PREFS_WEB_CONTENT "galeon-prefs-web-content"
#define GALEON_STOCK_PREFS_PRIVACY     "galeon-prefs-privacy"
#define GALEON_STOCK_PREFS_NETWORK     "galeon-prefs-network"

#define GALEON_PREFS_DIALOG_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_PREFS_DIALOG, GaleonPrefsDialogPrivate))


struct _GaleonPrefsDialogPrivate {
      guint       timeout_id;
      GtkWidget  *timeout_widget;

      GtkWidget  *general_homepage;

      GtkWidget  *language_entry;
      GtkWidget  *language_editor;

      gboolean    fonts_ignore_updates;
      char       *fonts_encoding;
      GtkWidget  *fonts_serif;
      GtkWidget  *fonts_sans;
      GtkWidget  *fonts_cursive;
      GtkWidget  *fonts_fantasy;
      GtkWidget  *fonts_monospace;
      GtkWidget  *fonts_proportional_size;
      GtkWidget  *fonts_monospace_size;
      GtkWidget  *fonts_minimum_size;
};

enum {
      REQUEST,    /* request a page from PDM, cert manager, etc. */
      LOCATION,   /* request the current location for home page  */
      LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE (GaleonPrefsDialog, galeon_prefs_dialog, GTK_TYPE_DIALOG)

static void
begin_busy (GaleonPrefsDialog *self)
{
      static GdkCursor *cursor = NULL;

      if (cursor == NULL) cursor = gdk_cursor_new (GDK_WATCH);

      if (!GTK_WIDGET_REALIZED(self)) gtk_widget_realize(GTK_WIDGET(self));

      gdk_window_set_cursor (GTK_WIDGET(self)->window, cursor);
      while (gtk_events_pending ()) gtk_main_iteration ();
}

static void
end_busy (GaleonPrefsDialog *self)
{
      gdk_window_set_cursor (GTK_WIDGET(self)->window, NULL);
}

static void
fill_combo_box_from_array (GtkWidget          *combobox,
                     const GulGuiOption *options,
                     guint               n_options)
{
      gul_gui_option_combobox_populate(GTK_COMBO_BOX(combobox),
                               options, n_options, FALSE, TRUE);
}

static void
on_combobox_changed (GtkComboBox *combobox, const char *gconf_key)
{
      gchar *value = gul_gui_option_combobox_get_value(combobox);

      if (value && value[0]) {
            eel_gconf_set_integer(gconf_key, atoi(value));
      }
      g_free(value);
}

/** connect_combobox:
 * 
 * Connect combo box options to GConf key.  Specialized version for handling
 * enums-as-ints as inherited from Galeon 1.2.*
 */
static void
connect_combobox(GtkWidget          *combobox,
             const char         *gconf_key,
             const GulGuiOption *options,
             guint               n_options)
{
      int  intval;
      char strval[8];

      g_return_if_fail(GTK_IS_COMBO_BOX(combobox));
      g_return_if_fail(gconf_key != NULL);

      fill_combo_box_from_array(combobox, options, n_options);

      intval = eel_gconf_get_integer(gconf_key);
      g_snprintf(strval, sizeof(strval), "%u", intval);
      gul_gui_option_combobox_set_value (GTK_COMBO_BOX(combobox), strval);

      g_signal_connect_data(G_OBJECT(combobox), "changed",
                        G_CALLBACK(on_combobox_changed),
                        g_strdup(gconf_key), (GClosureNotify)g_free, 0);
}

/************************************************************************
 * General page
 */
static void
galeon_prefs_general_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      self->priv->general_homepage =
            glade_xml_get_widget (gxml, "general_homepage_entry");

      gul_glade_gconf_connect_simple (gxml,
            "general_homepage_entry", CONF_GENERAL_HOMEPAGE,
            "general_session",        CONF_GENERAL_ALWAYS_SAVE_SESSION,
            NULL);

      gul_glade_gconf_connect_radio (gxml, CONF_GENERAL_NEWPAGE_TYPE,
            "general_new_home",  "0",
            "general_new_last",  "1",
            "general_new_blank", "2",
            NULL);
}

/* Glade callbacks (twice to shut up gcc...) */
void on_prefs_general_current_button_clicked (GtkWidget *button, GaleonPrefsDialog *dialog);
void on_prefs_general_reset_button_clicked   (GtkWidget *button, GaleonPrefsDialog *dialog);

void
on_prefs_general_reset_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      char *homepage;

      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      eel_gconf_unset (CONF_GENERAL_HOMEPAGE);

      /* the above would be sufficient had we connected gconf listeners... */
      homepage = eel_gconf_get_string (CONF_GENERAL_HOMEPAGE);
      gtk_entry_set_text (GTK_ENTRY(self->priv->general_homepage), homepage);
      g_free (homepage);
}

void
on_prefs_general_current_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      char *homepage;

      homepage = NULL;
      g_signal_emit (G_OBJECT(self), signals[LOCATION], 0, &homepage);
      g_return_if_fail (homepage != NULL);

      gtk_entry_set_text (GTK_ENTRY(self->priv->general_homepage), homepage);
      g_free (homepage);
}

/************************************************************************
 * Language page
 */
void on_prefs_language_edit_button_clicked (GtkWidget *button, GaleonPrefsDialog *self);

static void
language_entry_update (GtkWidget *entry, GSList *titles)
{
      GString *str;
      GSList  *l;

      g_return_if_fail (GTK_IS_ENTRY(entry));

      str = g_string_new ("");
      for (l = titles; l != NULL; l = l->next)
      {
            const char *title = l->data;

            g_string_append (str, title);
            if (l->next) g_string_append (str, ", ");
      }

      gtk_entry_set_text (GTK_ENTRY(entry), str->str);
      g_string_free (str, TRUE);
}

static char *
language_get_custom_title (const char *value)
{
      g_return_val_if_fail (value != NULL, NULL);
      return g_strdup_printf (_("Custom [%s]"), value);
}

static char *
language_get_title (const char *value, 
                gboolean make_up_title)
{
      char *name;

      g_return_val_if_fail (value != NULL, NULL);

      name = gul_iso_codes_lookup_name_for_code (value);
      if (name || make_up_title == FALSE)
      {
            return name;
      }

      return language_get_custom_title (value);
}

static char *
on_language_editor_title (GaleonLanguageEditor *editor, const char *value)
{
      return language_get_title (value, TRUE);
}

static GSList *
language_get_titles (GSList *values)
{
      GSList *titles, *l;

      titles = NULL;
      for (l = values; l != NULL; l = l->next)
      {
            const char *value = l->data;
            char       *title;

            title = language_get_title (value, TRUE);
            titles = g_slist_prepend (titles, title);
      }

      return g_slist_reverse (titles);
}

static void
language_entry_update_from_values (GtkWidget *entry, GSList *values)
{
      GSList *titles;

      titles = language_get_titles (values);

      language_entry_update (entry, titles);

      g_slist_foreach (titles, (GFunc)g_free, NULL);
      g_slist_free (titles);
}

static void
on_language_editor_changed (GaleonLanguageEditor *editor, GaleonPrefsDialog *self)
{
      GSList *values;
      GSList *titles;

      galeon_language_editor_get_selected (editor, &values, &titles);

      eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, values);
      language_entry_update (self->priv->language_entry, titles);

      g_slist_foreach (values, (GFunc)g_free, NULL);
      g_slist_free (values);
      g_slist_foreach (titles, (GFunc)g_free, NULL);
      g_slist_free (titles);
}

void
on_prefs_language_edit_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      GSList *values;
      gulong  handler_id;
      int     ret;

      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));

      values = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
      galeon_language_editor_set_selected 
            (GALEON_LANGUAGE_EDITOR(self->priv->language_editor), values);
      g_slist_foreach (values, (GFunc)g_free, NULL);
      g_slist_free (values);

      gtk_window_set_transient_for (GTK_WINDOW(self->priv->language_editor),
                                GTK_WINDOW(self));

      handler_id = g_signal_connect (G_OBJECT(self->priv->language_editor), 
                                 "changed",
                                 G_CALLBACK(on_language_editor_changed),
                               self);

      while (42)
      {
            ret = gtk_dialog_run (GTK_DIALOG(self->priv->language_editor));
            if (ret != GTK_RESPONSE_HELP) break;

            /* FIXME need docs */
      }

      gtk_widget_hide (self->priv->language_editor);

      g_signal_handler_disconnect (G_OBJECT(self->priv->language_editor),
                               handler_id);
}

static const GulGuiOption language_autodetects[] = {
      { N_("Off"),                 "0" },
      { N_("Chinese"),             "1" },
      { N_("East Asian"),          "2" },
      { N_("Japanese"),            "3" },
      { N_("Korean"),              "4" },
      { N_("Russian"),             "5" },
      { N_("Simplified Chinese"),  "6" },
      { N_("Traditional Chinese"), "7" },
      { N_("Ukrainian"),           "8" },
      { N_("Universal"),           "9" }
};

static void
on_language_default_charset_changed (GtkComboBox *combobox, GaleonPrefsDialog *self)
{
      char *value;

      value = gul_gui_option_combobox_get_value (combobox);
      g_return_if_fail (value != NULL);

      eel_gconf_set_string (CONF_LANGUAGE_DEFAULT_CHARSET, value);

      g_free(value);
}

static void
language_fill_charsets (GtkWidget *combobox, GList *charsets)
{
      GList     *l;
      GtkListStore *store;
      GtkTreeModel *model;

      g_return_if_fail (GTK_IS_COMBO_BOX(combobox));

      /* 
       * Adding rows produces a warning if this is not done. *sigh*
       */
      gtk_widget_realize(combobox);

      /* Populate the liststore before adding it to the combo, to
       * ensure it doesn't create thousands of GtkCellView's in
       * an O(n^2) operation (it re-creates the combo every time
       * an item is added */
      store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
      model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(store));
      g_object_unref (store);

      gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
                                   OPTION_COL_TITLE,
                                   GTK_SORT_ASCENDING);

      for (l = charsets; l != NULL; l = l->next)
      {
            GtkTreeIter iter;
            const GaleonEncodingInfo *info = l->data;

            gtk_list_store_append(store, &iter);
            gtk_list_store_set(store, &iter,
                           OPTION_COL_TITLE, _(info->title),
                           OPTION_COL_VALUE, info->encoding,
                           -1);
      }

        gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), model);
      g_object_unref (model);
      gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
}

static void
populate_language_editor (GaleonPrefsDialog *self)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      GulGuiOption *languages;
      guint i, n;
      const guint num_langs = G_N_ELEMENTS (galeon_prefs_dialog_languages);

      languages = g_new0 (GulGuiOption, num_langs);
      n = 0;
      for (i = 0; i < num_langs; i++)
      {
            gchar *title = language_get_title (galeon_prefs_dialog_languages[i], FALSE);
            if (title)
            {
                  languages[n].value = (char*)galeon_prefs_dialog_languages[i];
                  languages[n].title = title;
                  n++;
            }
      }

      galeon_language_editor_set_available
            (GALEON_LANGUAGE_EDITOR(p->language_editor), languages, n);

      for (i = 0; i < n; i++)
      {
            g_free ((char*)languages[i].title);
      }
      g_free (languages);
}

static void
galeon_prefs_language_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      GSList    *languages;
      GtkWidget *autodetect;
      GtkWidget *defcharset;
      GList     *charsets;
      char      *strval;
      GaleonEncodings *encodings;

      p->language_editor = galeon_language_editor_new ();

      populate_language_editor (self);
      g_signal_connect (G_OBJECT(p->language_editor), "title",
                    G_CALLBACK(on_language_editor_title), NULL);

      gul_glade_get_widgets (gxml,
            "language_languages",  &p->language_entry,
            "language_autodetect", &autodetect,
            "language_default",    &defcharset,
            NULL);

      g_return_if_fail (GTK_IS_ENTRY(p->language_entry));
      g_return_if_fail (GTK_IS_COMBO_BOX(autodetect));
      g_return_if_fail (GTK_IS_COMBO_BOX(defcharset));

      /* languages */

      languages = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
      language_entry_update_from_values (p->language_entry, languages);
      g_slist_foreach (languages, (GFunc)g_free, NULL);
      g_slist_free (languages);

      /* autodetect charsets */

      connect_combobox (autodetect, 
                    CONF_LANGUAGE_AUTODETECT_CHARSET,
                    language_autodetects,
                    G_N_ELEMENTS(language_autodetects));

      /* default charsets */
      encodings = galeon_embed_shell_get_encodings (embed_shell);
      charsets = galeon_encodings_get_encodings (encodings, LG_ALL);
      language_fill_charsets (defcharset, charsets);
      g_list_free (charsets);

      strval = eel_gconf_get_string (CONF_LANGUAGE_DEFAULT_CHARSET);
      if (strval)
      {
            gul_gui_option_combobox_set_value (GTK_COMBO_BOX(defcharset), strval);
            g_free (strval);
      }

      g_signal_connect (G_OBJECT(defcharset), "changed",
                    G_CALLBACK(on_language_default_charset_changed), self);
}

/************************************************************************
 * Tabs page
 */
static void
galeon_prefs_tabs_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      gul_glade_gconf_connect_simple (gxml,
            "tabs_tabbed", CONF_TABS_TABBED,
            "tabs_jump",   CONF_TABS_TABBED_AUTOJUMP,
            "tabs_popups", CONF_TABS_TABBED_POPUPS,
            "tabs_always", CONF_TABS_TABBED_ALWAYS_SHOW,
            NULL);
}

/************************************************************************
 * Web Content page
 */
void on_prefs_content_popups_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self);
void on_prefs_content_images_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self);

void
on_prefs_content_popups_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, GALEON_PREFS_MANAGE_POPUPS);
}

void
on_prefs_content_images_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, GALEON_PREFS_MANAGE_IMAGES);
}

static void
galeon_prefs_web_content_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      gul_glade_gconf_connect_simple (gxml,
            "content_java",       CONF_FILTERING_JAVA_ENABLED,
            "content_javascript", CONF_FILTERING_JAVASCRIPT_ENABLED,
            "content_popups",     CONF_FILTERING_ALLOW_POPUPS,
            "content_contextmenu",  CONF_FILTERING_ALLOW_CONTEXTMENU,
            NULL);
      gul_glade_gconf_connect_radio (gxml, CONF_FILTERING_IMAGE_LOADING_TYPE,
            "content_images_all",     "0",
            "content_images_visited", "1",
            "content_images_none",    "2",
            NULL);
      gul_glade_gconf_connect_radio (gxml, CONF_FILTERING_ANIMATE_TYPE,
            "content_animation_repeat", "0",
            "content_animation_once",   "1",
            "content_animation_none",   "2",
            NULL);
}

/************************************************************************
 * Privacy page
 */
void on_prefs_privacy_certificates_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self);
void on_prefs_privacy_cookies_manage_button_clicked      (GtkWidget *button, GaleonPrefsDialog *self);
void on_prefs_privacy_passwords_manage_button_clicked    (GtkWidget *button, GaleonPrefsDialog *self);

void
on_prefs_privacy_certificates_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, GALEON_PREFS_MANAGE_CERTIFICATES);
}
void
on_prefs_privacy_cookies_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, GALEON_PREFS_MANAGE_COOKIES);
}
void
on_prefs_privacy_passwords_manage_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, GALEON_PREFS_MANAGE_PASSWORDS);
}

static void
galeon_prefs_privacy_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      gul_glade_gconf_connect_radio (gxml, CONF_PERSISTENT_COOKIES_BEHAVIOR,
            "privacy_cookies_all",     "0",
            "privacy_cookies_visited", "1",
            "privacy_cookies_none",    "2",
            NULL);

      gul_glade_gconf_connect_radio (gxml, CONF_PERSISTENT_COOKIES_LIFETIME,
            "privacy_cookies_default_lifetime", "0",
                /*
                 * Side-effect abuse: These two keys set the same radio value but except_session
                 * also sets a bool. This is a mechanism to map mozilla's radio value + bool to
                 * appear to be just another radio value. The ordering of the radio buttons with
                 * the same value *must* be as follows, otherwise when the dialog is opened,
                 * the radio selection will always be on _except_session regardless of which one
                 * was really selected.
                 *
                 * With the following order, the radio is always on _ask but then the gconf bool
                 * is evaluated and if it's true, except_session is set to active which forces
                 * the radio to change. So we get away without any extra code :-)
                 */
            "privacy_cookies_ask_except_session",     "1",
            "privacy_cookies_ask",              "1",
            "privacy_cookies_expire",           "2",
            NULL);

      gul_glade_gconf_connect_simple (gxml,
            "privacy_cookies_ask_except_session", CONF_PERSISTENT_COOKIE_ACCEPT_SESSION,
            "privacy_passwords",      CONF_PERSISTENT_PASSWORDS_SAVE,
            NULL);
}

/************************************************************************
 * Fonts page
 */

static const GulGuiOption fonts_encodings[] = {
      { N_("Arabic"),              "ar"             },
      { N_("Greek"),               "el"             },
      { N_("Hebrew"),              "he"             },
      { N_("Japanese"),            "ja"             },
      { N_("Korean"),              "ko"             },
      { N_("Thai"),                "th"             },
      { N_("Turkish"),             "tr"             },
      { N_("Baltic"),              "x-baltic"       },
      { N_("Central European"),    "x-central-euro" },
      { N_("Cyrillic"),            "x-cyrillic"     },
      { N_("Devanagari"),          "x-devanagari"   },
      { N_("Tamil"),               "x-tamil"        },
      { N_("Unicode"),             "x-unicode"      },
      { N_("User Defined"),        "x-user-def"     },
      { N_("Western"),             "x-western"      },
      { N_("Simplified Chinese"),  "zh-CN"          },
      { N_("Traditional Chinese"), "zh-TW"          },
};

static void
fonts_make_gconf_key (char *buf, size_t bufsize,
                  const char *type, const char *encoding)
{
      g_snprintf (buf, bufsize, "%s_%s_%s", CONF_RENDERING_FONT, type, encoding);
}

static void
fonts_load_font (GaleonPrefsDialog *self, const char *type, GtkWidget *combo)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      char     gconf_key[256];
      char    *font;
      GList   *fonts = NULL, *rest = NULL, *l;
      gint index = -1;

      g_return_if_fail (GTK_IS_COMBO_BOX(combo));

      /* list all available fonts, show first those that are "good" for the
       * given encoding, after those show the remaining fonts */
      fonts = galeon_embed_shell_get_font_list (embed_shell, p->fonts_encoding, type);
      rest = galeon_embed_shell_get_font_list (embed_shell, "", type );

      for (l = rest; l != NULL; /* nothing */)
      {
            GList *next = l->next;

            if (g_list_find_custom (fonts, l->data, (GCompareFunc)strcmp))
            {
                  g_free (l->data);
                  rest = g_list_delete_link (rest, l);
            }
            l = next;
      }

      fonts = g_list_concat (fonts, rest);

      fonts_make_gconf_key (gconf_key, sizeof(gconf_key),
                        type, p->fonts_encoding);
      font = eel_gconf_get_string (gconf_key);
      if (font == NULL || !g_list_find_custom (fonts, font,
                                         (GCompareFunc)strcmp))
      {
            g_free (font);
            font = g_strdup (fonts != NULL ? fonts->data : "");
      }

      /* Clear out the old list before populating the new one */
      gtk_list_store_clear(GTK_LIST_STORE(
                  gtk_combo_box_get_model(GTK_COMBO_BOX(combo))));

      if (fonts == NULL)
      {
            gtk_widget_set_sensitive (combo, FALSE);
      }
      else
      {
            gint i = 0;

            gtk_widget_set_sensitive (combo, TRUE);
            for (l = fonts; l; l = l->next, i++)
            {
                  gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
                                      (char *)l->data);
                  if (strcmp(font, (char *)l->data) == 0)
                  {
                        index = i;
                  }
            }
      }
      g_list_foreach (fonts, (GFunc)g_free, NULL);
      g_list_free (fonts);

      /* 
       * If nothing was active, index defaults to -1 which does
       * the right now and selects nothing.
       */
      gtk_combo_box_set_active(GTK_COMBO_BOX(combo), index);
      g_free (font);
}

static void
fonts_load_font_size (GaleonPrefsDialog *self,
                  const char        *type,
                  GtkWidget         *spin_button,
                  int                default_size)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      char gconf_key[256];
      int  size;

      g_return_if_fail (GTK_IS_SPIN_BUTTON(spin_button));

      fonts_make_gconf_key (gconf_key, sizeof(gconf_key),
                        type, p->fonts_encoding);
      size = eel_gconf_get_integer (gconf_key);
      if (size == 0 && default_size > 0)
      {
            size = default_size;
      }

      gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_button), size);
}

static void
fonts_update_widgets (GaleonPrefsDialog *self)
{
      GaleonPrefsDialogPrivate *p = self->priv;

      /* this is going to take a while... */
      begin_busy (self);

      p->fonts_ignore_updates = TRUE;

      fonts_load_font (self, "serif",      p->fonts_serif);
      fonts_load_font (self, "sans-serif", p->fonts_sans);
      fonts_load_font (self, "cursive",    p->fonts_cursive);
      fonts_load_font (self, "fantasy",    p->fonts_fantasy);
      fonts_load_font (self, "monospace",  p->fonts_monospace);

      fonts_load_font_size (self, "variable_size",   p->fonts_proportional_size, 11);
      fonts_load_font_size (self, "monospace_size",  p->fonts_monospace_size,    10);
      fonts_load_font_size (self, "minimum_size",    p->fonts_minimum_size,      -1);

      p->fonts_ignore_updates = FALSE;

      end_busy (self);
}

static void
on_fonts_encoding_changed (GtkComboBox *combobox, GaleonPrefsDialog *self)
{
      GaleonPrefsDialogPrivate *p = self->priv;

      p->fonts_encoding = gul_gui_option_combobox_get_value (combobox);
      fonts_update_widgets (self);

      gul_state_set_string (STATE_FONTS_ENCODING, p->fonts_encoding);
}

static void
fonts_set_type_in_combo(GtkWidget *combo, const char *value)
{
      g_return_if_fail(GTK_IS_COMBO_BOX(combo));
      g_object_set_data(G_OBJECT(combo), "fonts-combo::type",
                        (gpointer)value);
}

static const char *
fonts_get_type_from_combo(GtkWidget *combo)
{
      g_return_val_if_fail(GTK_IS_COMBO_BOX(combo), NULL);
      return g_object_get_data(G_OBJECT(combo), "fonts-combo::type");
}

static void
on_fonts_combo_changed(GtkWidget *combo, GaleonPrefsDialog *self)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      const char *type, *font;
      char        gconf_key[256];
      GtkTreeIter iter;
      GtkTreeModel *model;

      g_return_if_fail(GTK_IS_COMBO_BOX(combo));

      if (p->fonts_ignore_updates) return;

      type = fonts_get_type_from_combo(combo);
      g_return_if_fail (type != NULL);

      model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
      if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter))
      {
            gtk_tree_model_get(model, &iter,
                               0, &font,
                               -1);
              g_return_if_fail(font || font[0]);
      }

      fonts_make_gconf_key(gconf_key, sizeof(gconf_key),
                       type, p->fonts_encoding);
      eel_gconf_set_string(gconf_key, font);
}

static void
fonts_connect_combo (GaleonPrefsDialog *self, GladeXML *gxml, 
                 const char *type,
                 const char *widget_name, GtkWidget **widget)
{
      *widget = glade_xml_get_widget(gxml, widget_name);
      g_return_if_fail(GTK_IS_COMBO_BOX(*widget));

      /*
       * HACK: Glade 2.5.x doesn't yet allow setting useful
       * properties on a GtkComboBoxEntry or the entry child
       * so we have to do it in code.
       */
      fonts_set_type_in_combo(*widget, type);

      g_signal_connect(G_OBJECT(*widget), "changed",
                   G_CALLBACK(on_fonts_combo_changed), self);
}

static void
fonts_set_type_in_spinbutton(GtkWidget *spin, const char *value)
{
      g_return_if_fail(GTK_IS_SPIN_BUTTON(spin));
      g_object_set_data(G_OBJECT(spin), "fonts-spinbutton::type",
                    (gpointer)value);
}

static const char *
fonts_get_type_from_spinbutton(GtkWidget *spin)
{
      g_return_val_if_fail(GTK_IS_SPIN_BUTTON(spin), NULL);
      return g_object_get_data(G_OBJECT(spin), "fonts-spinbutton::type");
}

static gboolean
fonts_timeout_func (gpointer data)
{
      GaleonPrefsDialog *self = data;
      GaleonPrefsDialogPrivate *p = self->priv;
      GtkWidget  *widget = p->timeout_widget;
      const char *type;
      char        gconf_key[256];
      int         size;

      g_return_val_if_fail (GTK_IS_SPIN_BUTTON(widget), FALSE);

      type = fonts_get_type_from_spinbutton(widget);
      g_return_val_if_fail (type != NULL, FALSE);

      size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(widget));
      fonts_make_gconf_key (gconf_key, sizeof(gconf_key),
                        type, p->fonts_encoding);
      eel_gconf_set_integer (gconf_key, size);

      p->timeout_id = 0;
      p->timeout_widget = NULL;

      return FALSE;
}

static void
fonts_timeout_start (GaleonPrefsDialog *self, GtkWidget *widget)
{
      GaleonPrefsDialogPrivate *p = self->priv;

      g_return_if_fail (p->timeout_id == 0);

      p->timeout_widget = widget;
      p->timeout_id = 
            g_timeout_add (FONTS_SPIN_TIMEOUT, fonts_timeout_func, self);
}

static void
fonts_timeout_stop (GaleonPrefsDialog *self, gboolean update)
{
      GaleonPrefsDialogPrivate *p = self->priv;

      if (p->timeout_id) 
      {
            g_source_remove (p->timeout_id);
            if (update)
            {
                  fonts_timeout_func (self);
            }
      }
      p->timeout_id = 0;
      p->timeout_widget = NULL;
}

static void
on_fonts_spinbutton_changed (GtkWidget *spin, GaleonPrefsDialog *self)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      const char *type;

      g_return_if_fail(GTK_IS_SPIN_BUTTON(spin));

      if (p->fonts_ignore_updates) return;

      type = fonts_get_type_from_spinbutton(spin);
      g_return_if_fail(type != NULL);

      /* we have to wait for a while before updating the gconf or the
       * spinbuttons will be ridiculously unresponsive thanks to
       * mozilla taking its time to reflow the page
       */
      fonts_timeout_stop(self, FALSE);
      fonts_timeout_start(self, spin);
}

static void
fonts_connect_spin_button (GaleonPrefsDialog *self, GladeXML *gxml, 
                       const char *type,
                     const char *widget_name, GtkWidget **widget)
{
      *widget = glade_xml_get_widget(gxml, widget_name);
      g_return_if_fail(GTK_IS_SPIN_BUTTON(*widget));

      fonts_set_type_in_spinbutton(*widget, type);

      g_signal_connect(G_OBJECT(*widget), "value-changed",
                   G_CALLBACK(on_fonts_spinbutton_changed), self);
}

static void
galeon_prefs_fonts_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      GaleonPrefsDialogPrivate *p = self->priv;
      GtkWidget *encoding;
      char      *tmp;

      gul_glade_size_group_widgets (gxml, GTK_SIZE_GROUP_HORIZONTAL,
            "fonts_proportional_label",
            "fonts_encoding_label",
            NULL);

      gul_glade_gconf_connect_radio (gxml, CONF_RENDERING_DEFAULT_FONT,
            "fonts_proportional_serif", "0",
            "fonts_proportional_sans",  "1",
            NULL);

      fonts_connect_combo (self, gxml, "serif",      "fonts_serif",
                       &p->fonts_serif);
      fonts_connect_combo (self, gxml, "sans-serif", "fonts_sans",
                       &p->fonts_sans);
      fonts_connect_combo (self, gxml, "cursive",    "fonts_cursive",
                       &p->fonts_cursive);
      fonts_connect_combo (self, gxml, "fantasy",    "fonts_fantasy",
                       &p->fonts_fantasy);
      fonts_connect_combo (self, gxml, "monospace",  "fonts_monospace",
                       &p->fonts_monospace);

      fonts_connect_spin_button (self, gxml, "variable_size",   
                             "fonts_proportional_size",
                           &p->fonts_proportional_size);
      fonts_connect_spin_button (self, gxml, "monospace_size",
                             "fonts_monospace_size",
                           &p->fonts_monospace_size);
      fonts_connect_spin_button (self, gxml, "minimum_size",
                             "fonts_minimum_size",
                           &p->fonts_minimum_size);

      encoding = glade_xml_get_widget (gxml, "fonts_encoding");
      fill_combo_box_from_array (encoding,
                             fonts_encodings,
                           G_N_ELEMENTS(fonts_encodings));

      tmp = gul_state_get_string (STATE_FONTS_ENCODING, "x-western");
      gul_gui_option_combobox_set_value (GTK_COMBO_BOX(encoding), tmp);
      g_free (tmp);

      g_signal_connect (G_OBJECT(encoding), "changed",
                    G_CALLBACK(on_fonts_encoding_changed), self);
      on_fonts_encoding_changed(GTK_COMBO_BOX(encoding), self);

      gul_glade_gconf_connect_simple (gxml,
            "fonts_always", CONF_RENDERING_USE_OWN_FONTS,
            NULL);
}

/************************************************************************
 * Mouse page
 */
static void
on_toggle_button_toggled_invert (GtkToggleButton *button, const char *gconf_key)
{
      eel_gconf_set_boolean (gconf_key, !gtk_toggle_button_get_active (button));
}

static const GulGuiOption mouse_middle_actions[] = {
      { N_("Bookmarks menu"),           "0" },
      { N_("Paste URL in new tab"),     "1" },
      { N_("Go Back"),                  "2" },
      { N_("Gestures"),                 "3" },
      { N_("Automatic scroll"),         "4" },
      { N_("Manual scroll"),            "5" },
      { N_("Paste URL in current tab"), "6" },
};

static void
galeon_prefs_mouse_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      GtkWidget *widget;

      /* middle button */

      widget = glade_xml_get_widget (gxml, "mouse_middle");
      connect_combobox (widget,
                    CONF_MOUSE_MIDDLE_BUTTON_ACTION,
                    mouse_middle_actions,
                    G_N_ELEMENTS(mouse_middle_actions));

      /* right button */

      gul_glade_gconf_connect_radio (gxml, CONF_MOUSE_RIGHT_BUTTON_ACTION,
            "mouse_right_context", "0",
            "mouse_right_gesture", "1",
            NULL);

      /* wheel */

      gul_glade_group_sensitive (gxml,
            "mouse_wheel_lines", GUL_SENSITIVE_FOLLOW,
            "mouse_wheel_override_hbox", NULL);
      gul_glade_group_sensitive (gxml,
            "mouse_wheel_override", GUL_SENSITIVE_FOLLOW,
            "mouse_wheel_num_lines_hbox", NULL);

      gul_glade_gconf_connect_radio (gxml, CONF_MOUSE_WHEEL_NOKEY_ACTION,
            "mouse_wheel_page",  "1",
            "mouse_wheel_lines", "0",
            NULL);
      gul_glade_gconf_connect_simple (gxml,
            "mouse_wheel_num_lines", CONF_MOUSE_WHEEL_NOKEY_STEP,
            NULL);

      widget = glade_xml_get_widget (gxml, "mouse_wheel_override");
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget),
            !eel_gconf_get_boolean (CONF_MOUSE_WHEEL_NOKEY_DEF_STEP));
      g_signal_connect (G_OBJECT(widget), "toggled",
                    G_CALLBACK(on_toggle_button_toggled_invert),
                    CONF_MOUSE_WHEEL_NOKEY_DEF_STEP);
}

/************************************************************************
 * Network page
 */
void on_prefs_network_clear_cache_button_clicked (GtkWidget *button, GaleonPrefsDialog *self);
void on_prefs_network_proxy_button_clicked (GtkWidget *button, GaleonPrefsDialog *self);

void
on_prefs_network_clear_cache_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      g_return_if_fail (GALEON_IS_PREFS_DIALOG(self));
      g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, GALEON_PREFS_CLEAR_CACHE);
}

void
on_prefs_network_proxy_button_clicked (GtkWidget *button, GaleonPrefsDialog *self)
{
      GtkWidget *parent;
      GtkWidget *dialog;
      GError        *err = NULL;

      if (g_spawn_command_line_async (GNOME_NETWORK_PREFERENCES, &err))
            return;

      parent = gtk_widget_get_toplevel (button);
      dialog = hig_alert_new (GTK_WINDOW(parent),
                        GTK_DIALOG_MODAL,
                        HIG_ALERT_ERROR,
                        _("Cannot start network proxy "
                          "configuration program."),
                        err->message,
                        GTK_STOCK_OK,
                        GTK_RESPONSE_OK,
                        NULL);
      g_clear_error (&err);

      gtk_dialog_run (GTK_DIALOG(dialog));
      gtk_widget_destroy (dialog);
}

static void
on_network_cache_size_changed (GtkSpinButton *spinbutton)
{
      int cache_mb;

      cache_mb = gtk_spin_button_get_value_as_int (spinbutton);
      eel_gconf_set_integer (CONF_NETWORK_DISK_CACHE, cache_mb*1024);
}

static void
galeon_prefs_network_construct (GaleonPrefsDialog *self, GladeXML *gxml)
{
      GtkWidget *spinbutton;
      GtkWidget *button;
      GtkWidget *warning;
      char      *path;
      int        size_kb;

      /* proxy */

      gul_glade_get_widgets (gxml,
            "prefs_network_proxy_button", &button,
            "proxy_warning",              &warning,
            NULL);

      path = g_find_program_in_path (GNOME_NETWORK_PREFERENCES);
      if (path != NULL)
      {
            gtk_widget_set_sensitive (button, TRUE);
            gtk_widget_hide (warning);
            g_free (path);
      }
      else
      {
            gtk_widget_set_sensitive (button, FALSE);
            gtk_widget_show (warning);
      }

      /* cache size */

      spinbutton = glade_xml_get_widget (gxml, "network_cache_size");
      g_return_if_fail (GTK_IS_SPIN_BUTTON(spinbutton));

      size_kb = eel_gconf_get_integer (CONF_NETWORK_DISK_CACHE);
      gtk_spin_button_set_value (GTK_SPIN_BUTTON(spinbutton), size_kb/1024);

      g_signal_connect (G_OBJECT(spinbutton), "value-changed",
                    G_CALLBACK(on_network_cache_size_changed), NULL);
}

/************************************************************************
 * GaleonPrefsDialog
 */


/* normally stock item labels should have mnemonics, but unlike with buttons
 * the underline would be visible in the treeview
 */
static const GtkStockItem stock_items[] = {
        { GALEON_STOCK_PREFS_GENERAL,     N_("General"),     0, 0, NULL },
        { GALEON_STOCK_PREFS_LANGUAGE,    N_("Language"),    0, 0, NULL },
        { GALEON_STOCK_PREFS_FONTS,       N_("Fonts"),       0, 0, NULL },
        { GALEON_STOCK_PREFS_TABS,        N_("Tabs"),        0, 0, NULL },
        { GALEON_STOCK_PREFS_MOUSE,       N_("Mouse"),       0, 0, NULL },
        { GALEON_STOCK_PREFS_WEB_CONTENT, N_("Web Content"), 0, 0, NULL },
        { GALEON_STOCK_PREFS_PRIVACY,     N_("Privacy"),     0, 0, NULL },
        { GALEON_STOCK_PREFS_NETWORK,     N_("Network"),     0, 0, NULL },
};

/* stock items */

static void
register_stock_icons (void)
{
      static gboolean been_there_done_that = FALSE;
      GtkIconFactory *factory;
      guint           i;

      if (been_there_done_that) return;
      been_there_done_that = TRUE;

      gtk_stock_add (stock_items, G_N_ELEMENTS(stock_items));

      factory = gtk_icon_factory_new ();
      gtk_icon_factory_add_default (factory);

      for (i = 0; i < G_N_ELEMENTS(stock_items); i++)
      {
            const GtkStockItem *item = &stock_items[i];
            GdkPixbuf  *pixbuf;
            GtkIconSet *icon_set;
            char       *fname;

            fname = g_strconcat (item->stock_id, ".png", NULL);
            pixbuf = gul_pixbuf_cache_get (fname);
            g_free (fname);

            icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
            gtk_icon_factory_add (factory, item->stock_id, icon_set);
            gtk_icon_set_unref (icon_set);

            g_object_unref (pixbuf);
      }

      g_object_unref (factory);
}

/* Sidebar */

enum {
      SIDEBAR_COL_ICON,
      SIDEBAR_COL_TEXT,
      SIDEBAR_COL_PAGE_NUM
};

static const char *sidebar_stock_ids[] = {
      GALEON_STOCK_PREFS_GENERAL,
      GALEON_STOCK_PREFS_LANGUAGE,
      GALEON_STOCK_PREFS_FONTS,
      GALEON_STOCK_PREFS_TABS,
      GALEON_STOCK_PREFS_MOUSE,
      GALEON_STOCK_PREFS_WEB_CONTENT,
      GALEON_STOCK_PREFS_PRIVACY,
      GALEON_STOCK_PREFS_NETWORK,
};

static void
sidebar_construct (GtkWidget *treeview)
{
      GtkTreeViewColumn *column;
      GtkCellRenderer   *renderer;
      GtkListStore      *store;
      guint              i;

      g_return_if_fail (GTK_IS_TREE_VIEW(treeview));

      /* model */

      store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);

      for (i = 0; i < G_N_ELEMENTS(sidebar_stock_ids); i++)
      {
            GtkStockItem item;
            GtkTreeIter  iter;

            g_assert (gtk_stock_lookup (sidebar_stock_ids[i], &item));

            gtk_list_store_append (store, &iter);
            gtk_list_store_set (store, &iter,
                            SIDEBAR_COL_ICON,     item.stock_id,
                            SIDEBAR_COL_TEXT,     _(item.label),
                            SIDEBAR_COL_PAGE_NUM, i,
                            -1);
      }

      /* view */

      column = gtk_tree_view_column_new ();

      renderer = gtk_cell_renderer_pixbuf_new ();
      gtk_tree_view_column_pack_start (column, renderer, FALSE);
      gtk_tree_view_column_add_attribute (column, renderer,
                                      "stock_id", SIDEBAR_COL_ICON);

      renderer = gtk_cell_renderer_text_new ();
      gtk_tree_view_column_pack_start (column, renderer, TRUE);
      gtk_tree_view_column_add_attribute (column, renderer,
                                      "text", SIDEBAR_COL_TEXT);

      gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);

      gtk_tree_view_set_model (GTK_TREE_VIEW(treeview),
                           GTK_TREE_MODEL(store));

      g_object_unref (store);
}

static void
on_sidebar_selection_changed (GtkTreeSelection *selection,
                          GtkNotebook      *notebook)
{
      GtkTreeModel *model;
      GtkTreeIter   iter;

      if (gtk_tree_selection_get_selected (selection, &model, &iter))
      {
            gint page_num;
            gtk_tree_model_get (model, &iter,
                            SIDEBAR_COL_PAGE_NUM, &page_num,
                            -1);
            gtk_notebook_set_current_page (notebook, page_num);
      }
}

static void
on_notebook_switch_page (GtkNotebook      *notebook,
                     GtkNotebookPage  *page,
                   guint             page_num,
                   GtkTreeSelection *selection)
{
      GtkTreeModel *model;
      GtkTreeIter   iter;

      gtk_tree_selection_get_selected (selection, &model, &iter);
      g_return_if_fail (gtk_tree_model_get_iter_first (model, &iter));

      do {
            guint i;
            gtk_tree_model_get (model, &iter, SIDEBAR_COL_PAGE_NUM, &i, -1);
            if (i == page_num)
            {
                  gtk_tree_selection_select_iter (selection, &iter);
                  return;
            }
      } while (gtk_tree_model_iter_next (model, &iter));

      g_return_if_reached ();
}

/** sidebar_link_with_notebook:
 * @treeview: a #GtkTreeView
 * @notebook: a #GtkNotebook
 *
 * Link sidebar treeview with the notebook so that the visible page always
 * matches the treeview selection.
 */
static void
sidebar_link_with_notebook (GtkWidget *treeview, GtkWidget *notebook)
{
      GtkTreeSelection *selection;

      g_return_if_fail (GTK_IS_TREE_VIEW(treeview));
      g_return_if_fail (GTK_IS_NOTEBOOK(notebook));

      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
      g_signal_connect (selection, "changed",
                    G_CALLBACK(on_sidebar_selection_changed), notebook);
      g_signal_connect (notebook, "switch_page",
                    G_CALLBACK(on_notebook_switch_page), selection);
}

/* GtkDialog */

static void
galeon_prefs_dialog_response (GtkDialog *dialog, gint response_id)
{
      if (response_id == GTK_RESPONSE_HELP)
      {
            gul_gui_help (GTK_WINDOW (dialog), "galeon.xml", "preferences");
            return;
      }

      gtk_widget_destroy (GTK_WIDGET(dialog));
}

/* GObject boilerplate */

GtkWidget *
galeon_prefs_dialog_new (void)
{
      GaleonPrefsDialog *self;

      self = GALEON_PREFS_DIALOG(g_object_new (
                  GALEON_TYPE_PREFS_DIALOG, 
                  "title",         _("Galeon Preferences"),
                  "has-separator", FALSE,
                  "resizable",     FALSE,
                  "border-width",  6,
                  NULL));
      gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(self)->vbox), 0);
      gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(self)->action_area), 6);

      gtk_dialog_add_buttons (GTK_DIALOG(self), 
                        GTK_STOCK_HELP,  GTK_RESPONSE_HELP,
                          GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                        NULL);

      return GTK_WIDGET(self);
}

static void
galeon_prefs_dialog_init (GaleonPrefsDialog *self)
{
      GladeXML  *gxml;
      GtkWidget *content;
      GtkWidget *treeview;
      GtkWidget *notebook;
      GtkWidget *glade_dialog;

      self->priv = GALEON_PREFS_DIALOG_GET_PRIVATE (self);

      self->priv->fonts_encoding = NULL;

      gxml = gul_glade_widget_new ("prefs-dialog.glade", "preferences_dialog", NULL, self);
      g_return_if_fail (gxml != NULL);

      gul_glade_get_widgets (gxml,
           "content_area",     &content,
           "sidebar_treeview", &treeview,
           "notebook",         &notebook,
           "preferences_dialog", &glade_dialog,
           NULL);

      gtk_widget_reparent (content, GTK_DIALOG(self)->vbox);

      sidebar_construct (treeview);
      sidebar_link_with_notebook (treeview, notebook);

      /* Keeping the notebook tabs visible in the glade file makes it easier
       * to edit, and keeping the HIGgy borders inside the notebook pages
       * makes it easier to use the notebook standalone.
       */
      gtk_notebook_set_show_tabs (GTK_NOTEBOOK(notebook), FALSE);
      g_list_foreach (gtk_container_get_children (GTK_CONTAINER(notebook)),
                  (GFunc)gtk_container_set_border_width,
                  GUINT_TO_POINTER(0));

      gul_glade_size_group_widgets (gxml, GTK_SIZE_GROUP_HORIZONTAL,
            "prefs_content_popups_manage_button",
            "prefs_content_images_manage_button",
            "prefs_privacy_passwords_manage_button",
            "prefs_privacy_cookies_manage_button",
            "prefs_privacy_certificates_manage_button",
            "prefs_network_clear_cache_button",
            NULL);

      galeon_prefs_general_construct (self, gxml);
      galeon_prefs_language_construct (self, gxml);
      galeon_prefs_fonts_construct (self, gxml);
      galeon_prefs_tabs_construct (self, gxml);
      galeon_prefs_mouse_construct (self, gxml);
      galeon_prefs_web_content_construct (self, gxml);
      galeon_prefs_privacy_construct (self, gxml);
      galeon_prefs_network_construct (self, gxml);

      g_object_unref (gxml);

      gtk_widget_destroy (glade_dialog);
}

static void
galeon_prefs_dialog_destroy (GtkObject *object)
{
      GaleonPrefsDialog *self = GALEON_PREFS_DIALOG(object);

      fonts_timeout_stop (self, TRUE);

      GTK_OBJECT_CLASS(galeon_prefs_dialog_parent_class)->destroy (object);
}

static void
galeon_prefs_dialog_finalize (GObject *object)
{
      GaleonPrefsDialog *self = GALEON_PREFS_DIALOG(object);

      g_free (self->priv->fonts_encoding);
      gtk_widget_destroy (self->priv->language_editor);

      G_OBJECT_CLASS(galeon_prefs_dialog_parent_class)->finalize (object);
}

static void
galeon_prefs_dialog_class_init (GaleonPrefsDialogClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS(klass);
      GtkObjectClass *gtkobj_class = GTK_OBJECT_CLASS(klass);
      GtkDialogClass *dialog_class = GTK_DIALOG_CLASS(klass);


      object_class->finalize = galeon_prefs_dialog_finalize;
      gtkobj_class->destroy = galeon_prefs_dialog_destroy;
      dialog_class->response = galeon_prefs_dialog_response;

      signals[REQUEST] =
            g_signal_new ("request",
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GaleonPrefsDialogClass, request),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__UINT,
                  G_TYPE_NONE, 1,
                  G_TYPE_UINT);

      signals[LOCATION] =
            g_signal_new ("location",
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GaleonPrefsDialogClass, location),
                  NULL, NULL,
                  galeon_marshal_STRING__VOID,
                  G_TYPE_STRING, 0);

      register_stock_icons ();

      g_type_class_add_private (klass, sizeof (GaleonPrefsDialogPrivate));
}


Generated by  Doxygen 1.6.0   Back to index