aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <mpeseng@src.gnome.org>2002-12-31 03:29:24 +0800
committerMarco Pesenti Gritti <mpeseng@src.gnome.org>2002-12-31 03:29:24 +0800
commit6876ede98282c7db318089bfefb292aa59e55d48 (patch)
tree76b23252d04da232d0ebf22e53bfe3e022686af9 /src
downloadgsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar
gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.gz
gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.bz2
gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.lz
gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.xz
gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.tar.zst
gsoc2013-epiphany-6876ede98282c7db318089bfefb292aa59e55d48.zip
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/.cvsignore6
-rw-r--r--src/Makefile.am101
-rwxr-xr-xsrc/appearance-prefs.c458
-rw-r--r--src/appearance-prefs.h58
-rw-r--r--src/bookmarks/.cvsignore6
-rw-r--r--src/bookmarks/Makefile.am31
-rw-r--r--src/bookmarks/ephy-bookmarks-editor.c534
-rw-r--r--src/bookmarks/ephy-bookmarks-editor.h59
-rw-r--r--src/bookmarks/ephy-bookmarks.c988
-rw-r--r--src/bookmarks/ephy-bookmarks.h108
-rw-r--r--src/bookmarks/ephy-keywords-entry.c286
-rw-r--r--src/bookmarks/ephy-keywords-entry.h68
-rw-r--r--src/bookmarks/ephy-new-bookmark.c340
-rw-r--r--src/bookmarks/ephy-new-bookmark.h65
-rw-r--r--src/bookmarks/ephy-node-view.c531
-rw-r--r--src/bookmarks/ephy-node-view.h82
-rw-r--r--src/bookmarks/ephy-tree-model-node.c702
-rw-r--r--src/bookmarks/ephy-tree-model-node.h81
-rw-r--r--src/ephy-automation.c217
-rw-r--r--src/ephy-automation.h52
-rw-r--r--src/ephy-favorites-menu.c275
-rw-r--r--src/ephy-favorites-menu.h66
-rw-r--r--src/ephy-history-model.c838
-rw-r--r--src/ephy-history-model.h84
-rw-r--r--src/ephy-main.c340
-rw-r--r--src/ephy-nautilus-view.c954
-rw-r--r--src/ephy-nautilus-view.h84
-rw-r--r--src/ephy-shell.c525
-rw-r--r--src/ephy-shell.h101
-rw-r--r--src/ephy-tab.c945
-rw-r--r--src/ephy-tab.h105
-rw-r--r--src/ephy-window.c1428
-rw-r--r--src/ephy-window.h140
-rwxr-xr-xsrc/general-prefs.c484
-rw-r--r--src/general-prefs.h58
-rwxr-xr-xsrc/history-dialog.c478
-rw-r--r--src/history-dialog.h63
-rw-r--r--src/language-editor.c388
-rw-r--r--src/language-editor.h67
-rwxr-xr-xsrc/pdm-dialog.c669
-rw-r--r--src/pdm-dialog.h56
-rw-r--r--src/popup-commands.c222
-rw-r--r--src/popup-commands.h58
-rwxr-xr-xsrc/ppview-toolbar.c388
-rw-r--r--src/ppview-toolbar.h63
-rw-r--r--src/prefs-dialog.c335
-rw-r--r--src/prefs-dialog.h63
-rw-r--r--src/session.c690
-rw-r--r--src/session.h84
-rwxr-xr-xsrc/statusbar.c321
-rw-r--r--src/statusbar.h70
-rwxr-xr-xsrc/toolbar.c982
-rw-r--r--src/toolbar.h88
-rwxr-xr-xsrc/ui-prefs.c232
-rw-r--r--src/ui-prefs.h58
-rw-r--r--src/window-commands.c917
-rw-r--r--src/window-commands.h196
57 files changed, 17688 insertions, 0 deletions
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 000000000..27d9d0cd0
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,6 @@
+*.o
+Makefile
+Makefile.in
+.deps
+.libs
+epiphany
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 000000000..5ec49453d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,101 @@
+SUBDIRS = bookmarks
+
+INCLUDES = \
+ -I$(top_srcdir)/embed \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/lib/widgets \
+ -I$(top_srcdir)/lib/toolbar \
+ -I$(top_srcdir)/src/bookmarks \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DPIXMAP_DIR=\""$(datadir)/pixmaps"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+bin_PROGRAMS = epiphany
+
+CXXLD = $(CXX)
+LINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+
+
+ephy_automation_interface_idl_sources = \
+ EphyAutomation-common.c \
+ EphyAutomation-stubs.c \
+ EphyAutomation-skels.c \
+ EphyAutomation.h
+
+if ENABLE_NAUTILUS_VIEW
+nautilus_view_sources = \
+ ephy-nautilus-view.c \
+ ephy-nautilus-view.h
+else
+nautilus_view_sources =
+endif
+
+epiphany_SOURCES = \
+ $(ephy_automation_interface_idl_sources) \
+ $(nautilus_view_sources) \
+ ui-prefs.c \
+ ui-prefs.h \
+ prefs-dialog.c \
+ prefs-dialog.h \
+ toolbar.c \
+ toolbar.h \
+ statusbar.c \
+ statusbar.h \
+ ephy-main.c \
+ ephy-automation.c \
+ ephy-automation.h \
+ ephy-shell.c \
+ ephy-shell.h \
+ ephy-tab.c \
+ ephy-tab.h \
+ ephy-window.c \
+ ephy-window.h \
+ window-commands.c \
+ window-commands.h \
+ popup-commands.c \
+ popup-commands.h \
+ history-dialog.c \
+ history-dialog.h \
+ ppview-toolbar.c \
+ ppview-toolbar.h \
+ session.c \
+ session.h \
+ general-prefs.c \
+ general-prefs.h \
+ language-editor.c \
+ language-editor.h \
+ appearance-prefs.c \
+ appearance-prefs.h \
+ pdm-dialog.c \
+ pdm-dialog.h \
+ ephy-favorites-menu.c \
+ ephy-favorites-menu.h \
+ ephy-history-model.c \
+ ephy-history-model.h
+
+epiphany_LDADD = \
+ $(top_builddir)/embed/libephyembed.la \
+ $(top_builddir)/lib/libephy.la \
+ $(top_builddir)/src/bookmarks/libephybookmarks.la \
+ $(MOZILLA_COMPONENT_LIBS) \
+ $(EPIPHANY_DEPENDENCY_LIBS) \
+ $(INTLLIBS)
+
+
+BUILT_SOURCES= \
+ EphyAutomation.h EphyAutomation-common.c EphyAutomation-stubs.c EphyAutomation-skels.c
+
+CLEAN_FILES = $(BUILT_SOURCES)
+
+EphyAutomation-common.c EphyAutomation-stubs.c EphyAutomation-skels.c EphyAutomation.h: $(top_srcdir)/idl/EphyAutomation.idl
+ $(ORBIT_IDL) -I $(LIBBONOBO_IDL) -I $(BONOBO_ACTIVATION_IDL) $(top_srcdir)/idl/EphyAutomation.idl
+
+EXTRA_DIST = $(top_srcdir)/idl/EphyAutomation.idl
diff --git a/src/appearance-prefs.c b/src/appearance-prefs.c
new file mode 100755
index 000000000..da1056f3f
--- /dev/null
+++ b/src/appearance-prefs.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "appearance-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include <string.h>
+#include <gtk/gtkcombo.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkoptionmenu.h>
+
+static void appearance_prefs_class_init (AppearancePrefsClass *klass);
+static void appearance_prefs_init (AppearancePrefs *dialog);
+static void appearance_prefs_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+fonts_language_optionmenu_changed_cb (GtkWidget *optionmenu, EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct AppearancePrefsPrivate
+{
+ int language;
+ gboolean switching;
+};
+
+enum
+{
+ SERIF_PROP,
+ SANSSERIF_PROP,
+ MONOSPACE_PROP,
+ FIXED_SIZE_PROP,
+ VARIABLE_SIZE_PROP,
+ MIN_SIZE_PROP,
+ PROPORTIONAL_PROP,
+ BACKGROUND_PROP,
+ TEXT_PROP,
+ UNVISITED_PROP,
+ VISITED_PROP,
+ USE_SYSCOLORS_PROP,
+ USE_COLORS_PROP,
+ USE_FONTS_PROP,
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { SERIF_PROP, "serif_combo", NULL, PT_NORMAL, NULL },
+ { SANSSERIF_PROP, "sansserif_combo", NULL, PT_NORMAL, NULL },
+ { MONOSPACE_PROP, "monospace_combo", NULL, PT_NORMAL, NULL },
+ { FIXED_SIZE_PROP, "fixed_size_spinbutton", NULL, PT_NORMAL, NULL },
+ { VARIABLE_SIZE_PROP, "variable_size_spinbutton", NULL, PT_NORMAL, NULL },
+ { MIN_SIZE_PROP, "min_size_spinbutton", NULL, PT_NORMAL, NULL },
+ { PROPORTIONAL_PROP, "proportional_optionmenu", CONF_RENDERING_DEFAULT_FONT, PT_AUTOAPPLY, NULL },
+ { BACKGROUND_PROP, "background_cpick", CONF_RENDERING_BG_COLOR, PT_AUTOAPPLY, NULL },
+ { TEXT_PROP, "text_cpick", CONF_RENDERING_TEXT_COLOR, PT_AUTOAPPLY, NULL },
+ { UNVISITED_PROP, "unvisited_cpick", CONF_RENDERING_UNVISITED_LINKS, PT_AUTOAPPLY, NULL },
+ { VISITED_PROP, "visited_cpick", CONF_RENDERING_VISITED_LINKS, PT_AUTOAPPLY, NULL },
+ { USE_SYSCOLORS_PROP, "use_syscolors_checkbutton", CONF_RENDERING_USE_SYSTEM_COLORS, PT_AUTOAPPLY, NULL },
+ { USE_COLORS_PROP, "use_colors_checkbutton", CONF_RENDERING_USE_OWN_COLORS, PT_AUTOAPPLY, NULL },
+ { USE_FONTS_PROP, "use_fonts_checkbutton", CONF_RENDERING_USE_OWN_FONTS, PT_AUTOAPPLY, NULL },
+
+ { -1, NULL, NULL }
+};
+
+/* FIXME duped in mozilla/ */
+const
+char *lang_encode[] =
+{
+ "x-western",
+ "x-central-euro",
+ "ja",
+ "zh-TW",
+ "zh-CN",
+ "ko",
+ "x-cyrillic",
+ "x-baltic",
+ "el",
+ "tr",
+ "x-unicode",
+ "th",
+ "he",
+ "ar"
+};
+
+enum
+{
+ FONT_TYPE_SERIF,
+ FONT_TYPE_SANSSERIF,
+ FONT_TYPE_MONOSPACE
+};
+
+const
+char *fonts_types[] =
+{
+ "serif",
+ "sans-serif",
+ "monospace"
+};
+
+enum
+{
+ FONT_SIZE_FIXED,
+ FONT_SIZE_VAR,
+ FONT_SIZE_MIN
+};
+
+const
+char *size_prefs[] =
+{
+ CONF_RENDERING_FONT_FIXED_SIZE,
+ CONF_RENDERING_FONT_VAR_SIZE,
+ CONF_RENDERING_FONT_MIN_SIZE
+};
+
+GType
+appearance_prefs_get_type (void)
+{
+ static GType appearance_prefs_type = 0;
+
+ if (appearance_prefs_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (AppearancePrefsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) appearance_prefs_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (AppearancePrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) appearance_prefs_init
+ };
+
+ appearance_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "AppearancePrefs",
+ &our_info, 0);
+ }
+
+ return appearance_prefs_type;
+
+}
+
+static void
+appearance_prefs_class_init (AppearancePrefsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = appearance_prefs_finalize;
+}
+
+static void
+setup_font_menu (AppearancePrefs *dialog,
+ const char *type,
+ GtkWidget *combo)
+{
+ char *default_font;
+ GList *fonts;
+ EphyEmbedShell *shell;
+ const char *name;
+ char key[255];
+ int pos;
+ GtkWidget *entry = GTK_COMBO(combo)->entry;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+
+ ephy_embed_shell_get_font_list (shell,
+ lang_encode[dialog->priv->language],
+ type, &fonts, &default_font);
+
+ /* Get the default font */
+ sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT, type,
+ lang_encode[dialog->priv->language]);
+ name = eel_gconf_get_string (key);
+ if (name == NULL)
+ {
+ name = default_font;
+ }
+
+ /* put the default font at the top in the list */
+ if (name != NULL)
+ {
+ fonts = g_list_prepend (fonts,
+ (gpointer)g_strdup(name));
+ }
+
+ /* set popdown doesnt like NULL */
+ if (fonts == NULL)
+ {
+ fonts = g_list_alloc ();
+ }
+
+ gtk_combo_set_popdown_strings (GTK_COMBO(combo), fonts);
+
+ /* set the default value */
+ if (name != NULL)
+ {
+ gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
+ gtk_editable_insert_text (GTK_EDITABLE(entry),
+ name, g_utf8_strlen (name, -1),
+ &pos);
+ }
+
+ g_free (default_font);
+
+ /* FIXME free the list */
+}
+
+static void
+save_font_menu (AppearancePrefs *dialog,
+ int type,
+ GtkWidget *entry)
+{
+ char *name;
+ char key[255];
+
+ name = gtk_editable_get_chars
+ (GTK_EDITABLE(entry), 0, -1);
+
+ /* do not save empty fonts */
+ if (!name || *name == '\0')
+ {
+ g_free (name);
+ return;
+ }
+
+ sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT,
+ fonts_types[type],
+ lang_encode[dialog->priv->language]);
+ eel_gconf_set_string (key, name);
+ g_free (name);
+}
+
+static void
+font_entry_changed_cb (GtkWidget *entry, AppearancePrefs *dialog)
+{
+ int type;
+
+ if (dialog->priv->switching) return;
+
+ type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(entry),
+ "type"));
+ save_font_menu (dialog, type, entry);
+}
+
+static void
+attach_font_signal (AppearancePrefs *dialog, int prop,
+ gpointer type)
+{
+ GtkWidget *combo;
+ GtkWidget *entry;
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ prop);
+ entry = GTK_COMBO(combo)->entry;
+ g_object_set_data (G_OBJECT(entry), "type", type);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK(font_entry_changed_cb),
+ dialog);
+}
+
+static void
+attach_fonts_signals (AppearancePrefs *dialog)
+{
+ attach_font_signal (dialog, SERIF_PROP,
+ GINT_TO_POINTER(FONT_TYPE_SERIF));
+ attach_font_signal (dialog, SANSSERIF_PROP,
+ GINT_TO_POINTER(FONT_TYPE_SANSSERIF));
+ attach_font_signal (dialog, MONOSPACE_PROP,
+ GINT_TO_POINTER(FONT_TYPE_MONOSPACE));
+}
+
+static void
+size_spinbutton_changed_cb (GtkWidget *spin, AppearancePrefs *dialog)
+{
+ int type;
+ char key[255];
+
+ if (dialog->priv->switching) return;
+
+ type = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(spin), "type"));
+
+ sprintf (key, "%s_%s",
+ size_prefs[type],
+ lang_encode[dialog->priv->language]);
+ eel_gconf_set_integer (key, gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin)));
+}
+
+static void
+attach_size_controls_signals (AppearancePrefs *dialog)
+{
+ GtkWidget *spin;
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ FIXED_SIZE_PROP);
+ g_object_set_data (G_OBJECT(spin), "type",
+ GINT_TO_POINTER(FONT_SIZE_FIXED));
+ g_signal_connect (spin, "value_changed",
+ G_CALLBACK(size_spinbutton_changed_cb),
+ dialog);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ VARIABLE_SIZE_PROP);
+ g_object_set_data (G_OBJECT(spin), "type",
+ GINT_TO_POINTER(FONT_SIZE_VAR));
+ g_signal_connect (spin, "value_changed",
+ G_CALLBACK(size_spinbutton_changed_cb),
+ dialog);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ MIN_SIZE_PROP);
+ g_object_set_data (G_OBJECT(spin), "type",
+ GINT_TO_POINTER(FONT_SIZE_MIN));
+ g_signal_connect (spin, "value_changed",
+ G_CALLBACK(size_spinbutton_changed_cb),
+ dialog);
+}
+
+static void
+setup_size_control (AppearancePrefs *dialog,
+ const char *pref,
+ int default_size,
+ GtkWidget *spin)
+{
+ char key[255];
+ int size;
+
+ sprintf (key, "%s_%s", pref,
+ lang_encode[dialog->priv->language]);
+ size = eel_gconf_get_integer (key);
+
+ if (size == 0) size = default_size;
+
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin), size);
+}
+
+static void
+setup_size_controls (AppearancePrefs *dialog)
+{
+ GtkWidget *spin;
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ FIXED_SIZE_PROP);
+ setup_size_control (dialog, CONF_RENDERING_FONT_FIXED_SIZE, 12, spin);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ VARIABLE_SIZE_PROP);
+ setup_size_control (dialog, CONF_RENDERING_FONT_VAR_SIZE, 16, spin);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ MIN_SIZE_PROP);
+ setup_size_control (dialog, CONF_RENDERING_FONT_MIN_SIZE, 0, spin);
+}
+
+static void
+setup_fonts (AppearancePrefs *dialog)
+{
+ GtkWidget *combo;
+
+ dialog->priv->switching = TRUE;
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ SERIF_PROP);
+ setup_font_menu (dialog, "serif", combo);
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ SANSSERIF_PROP);
+ setup_font_menu (dialog, "sans-serif", combo);
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ MONOSPACE_PROP);
+ setup_font_menu (dialog, "monospace", combo);
+
+ dialog->priv->switching = FALSE;
+}
+
+static void
+appearance_prefs_init (AppearancePrefs *dialog)
+{
+ dialog->priv = g_new0 (AppearancePrefsPrivate, 1);
+ dialog->priv->switching = FALSE;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "prefs-dialog.glade",
+ "appearance_page_box");
+
+ setup_fonts (dialog);
+ setup_size_controls (dialog);
+ attach_fonts_signals (dialog);
+ attach_size_controls_signals (dialog);
+}
+
+static void
+appearance_prefs_finalize (GObject *object)
+{
+ AppearancePrefs *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_appearance_PREFS (object));
+
+ dialog = appearance_PREFS (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+appearance_prefs_new (void)
+{
+ AppearancePrefs *dialog;
+
+ dialog = appearance_PREFS (g_object_new (appearance_PREFS_TYPE,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+fonts_language_optionmenu_changed_cb (GtkWidget *optionmenu,
+ EphyDialog *dialog)
+{
+ int i;
+
+ i = gtk_option_menu_get_history
+ (GTK_OPTION_MENU (optionmenu));
+
+ appearance_PREFS(dialog)->priv->language = i;
+
+ setup_fonts (appearance_PREFS(dialog));
+ setup_size_controls (appearance_PREFS(dialog));
+}
diff --git a/src/appearance-prefs.h b/src/appearance-prefs.h
new file mode 100644
index 000000000..17067b7e9
--- /dev/null
+++ b/src/appearance-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef APPEARANCE_PREFS_H
+#define APPEARANCE_PREFS_H
+
+#include "ephy-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct AppearancePrefs AppearancePrefs;
+typedef struct AppearancePrefsClass AppearancePrefsClass;
+
+#define appearance_PREFS_TYPE (appearance_prefs_get_type ())
+#define appearance_PREFS(obj) (GTK_CHECK_CAST ((obj), appearance_PREFS_TYPE, AppearancePrefs))
+#define appearance_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), appearance_PREFS, AppearancePrefsClass))
+#define IS_appearance_PREFS(obj) (GTK_CHECK_TYPE ((obj), appearance_PREFS_TYPE))
+#define IS_appearance_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), appearance_PREFS))
+
+typedef struct AppearancePrefsPrivate AppearancePrefsPrivate;
+
+struct AppearancePrefs
+{
+ EphyDialog parent;
+ AppearancePrefsPrivate *priv;
+};
+
+struct AppearancePrefsClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType appearance_prefs_get_type (void);
+
+EphyDialog *appearance_prefs_new (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/bookmarks/.cvsignore b/src/bookmarks/.cvsignore
new file mode 100644
index 000000000..6e5ca7ed4
--- /dev/null
+++ b/src/bookmarks/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+.deps
+.libs
+*.lo
+*.la
diff --git a/src/bookmarks/Makefile.am b/src/bookmarks/Makefile.am
new file mode 100644
index 000000000..4dd24c1bd
--- /dev/null
+++ b/src/bookmarks/Makefile.am
@@ -0,0 +1,31 @@
+INCLUDES = \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/embed \
+ -I$(top_srcdir)/lib/widgets \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libephybookmarks.la
+
+libephybookmarks_la_SOURCES = \
+ ephy-bookmarks.c \
+ ephy-bookmarks.h \
+ ephy-tree-model-node.c \
+ ephy-tree-model-node.h \
+ ephy-node-view.c \
+ ephy-node-view.h \
+ ephy-bookmarks-editor.c \
+ ephy-bookmarks-editor.h \
+ ephy-keywords-entry.c \
+ ephy-keywords-entry.h \
+ ephy-new-bookmark.c \
+ ephy-new-bookmark.h
diff --git a/src/bookmarks/ephy-bookmarks-editor.c b/src/bookmarks/ephy-bookmarks-editor.c
new file mode 100644
index 000000000..2888950df
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks-editor.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gtk/gtktable.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+
+#include "ephy-bookmarks-editor.h"
+#include "ephy-node-view.h"
+#include "ephy-window.h"
+#include "ephy-keywords-entry.h"
+#include "ephy-dnd.h"
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+static void ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass);
+static void ephy_bookmarks_editor_init (EphyBookmarksEditor *editor);
+static void ephy_bookmarks_editor_finalize (GObject *object);
+static void ephy_bookmarks_editor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_bookmarks_editor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyBookmarksEditorPrivate
+{
+ EphyBookmarks *bookmarks;
+ EphyNodeView *bm_view;
+ EphyNodeView *key_view;
+ EphyNodeFilter *bookmarks_filter;
+ GtkWidget *title_entry;
+ GtkWidget *keywords_entry;
+ GtkWidget *search_entry;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BOOKMARKS
+};
+
+enum
+{
+ RESPONSE_REMOVE
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_bookmarks_editor_get_type (void)
+{
+ static GType ephy_bookmarks_editor_type = 0;
+
+ if (ephy_bookmarks_editor_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyBookmarksEditorClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_bookmarks_editor_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyBookmarksEditor),
+ 0,
+ (GInstanceInitFunc) ephy_bookmarks_editor_init
+ };
+
+ ephy_bookmarks_editor_type = g_type_register_static (GTK_TYPE_DIALOG,
+ "EphyBookmarksEditor",
+ &our_info, 0);
+ }
+
+ return ephy_bookmarks_editor_type;
+}
+
+static void
+ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_bookmarks_editor_finalize;
+
+ object_class->set_property = ephy_bookmarks_editor_set_property;
+ object_class->get_property = ephy_bookmarks_editor_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BOOKMARKS,
+ g_param_spec_object ("bookmarks",
+ "Bookmarks set",
+ "Bookmarks set",
+ EPHY_BOOKMARKS_TYPE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_bookmarks_editor_finalize (GObject *object)
+{
+ EphyBookmarksEditor *editor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_BOOKMARKS_EDITOR (object));
+
+ editor = EPHY_BOOKMARKS_EDITOR (object);
+
+ g_return_if_fail (editor->priv != NULL);
+
+ g_object_unref (G_OBJECT (editor->priv->bookmarks_filter));
+
+ g_free (editor->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_bookmarks_editor_node_selected_cb (GtkWidget *view,
+ EphyNode *node,
+ EphyBookmarksEditor *editor)
+{
+ const char *title;
+ const char *keywords;
+
+ if (node != NULL)
+ {
+ g_assert (EPHY_IS_NODE (node));
+
+ title = ephy_node_get_property_string
+ (node, EPHY_NODE_BMK_PROP_TITLE);
+ keywords = ephy_node_get_property_string
+ (node, EPHY_NODE_BMK_PROP_KEYWORDS);
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->title_entry),
+ title ? g_strdup (title) : "");
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->keywords_entry),
+ keywords ? g_strdup (keywords) : "");
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->title_entry), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->keywords_entry), TRUE);
+ }
+ else
+ {
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->title_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->keywords_entry), "");
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->title_entry), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->keywords_entry), FALSE);
+ }
+}
+
+static void
+ephy_bookmarks_editor_node_activated_cb (GtkWidget *view,
+ EphyNode *node,
+ EphyBookmarksEditor *editor)
+{
+ const char *location;
+ GtkWindow *window;
+
+ g_return_if_fail (EPHY_IS_NODE (node));
+ location = ephy_node_get_property_string
+ (node, EPHY_NODE_BMK_PROP_LOCATION);
+ g_return_if_fail (location != NULL);
+
+ window = gtk_window_get_transient_for (GTK_WINDOW (editor));
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+ ephy_window_load_url (EPHY_WINDOW (window), location);
+}
+
+static void
+ephy_bookmarks_editor_response_cb (GtkDialog *dialog,
+ int response_id,
+ EphyBookmarksEditor *editor)
+{
+ switch (response_id)
+ {
+ case GTK_RESPONSE_CLOSE:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+ case RESPONSE_REMOVE:
+ ephy_node_view_remove (editor->priv->bm_view);
+ break;
+ }
+}
+
+static void
+update_prop_from_entry (EphyBookmarksEditor *editor,
+ GtkWidget *entry,
+ guint id)
+{
+ GList *selection;
+ GValue value = { 0, };
+
+ selection = ephy_node_view_get_selection (editor->priv->bm_view);
+ if (selection)
+ {
+ EphyNode *bm = EPHY_NODE (selection->data);
+ char *tmp;
+
+ tmp = gtk_editable_get_chars
+ (GTK_EDITABLE (entry), 0, -1);
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, tmp);
+ ephy_node_set_property (bm, id, &value);
+ g_value_unset (&value);
+ g_free (tmp);
+ }
+ g_list_free (selection);
+}
+
+static void
+title_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor)
+{
+ update_prop_from_entry (editor, editor->priv->title_entry,
+ EPHY_NODE_BMK_PROP_TITLE);
+}
+
+static void
+keywords_changed_cb (GtkWidget *entry,
+ EphyBookmarksEditor *editor)
+{
+ EphyNode *node;
+ GList *selection;
+ char *keywords;
+
+ selection = ephy_node_view_get_selection (editor->priv->bm_view);
+ if (selection == NULL) return;
+ node = EPHY_NODE (selection->data);
+ g_list_free (selection);
+
+ keywords = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+ ephy_bookmarks_update_keywords (editor->priv->bookmarks,
+ keywords, node);
+ g_free (keywords);
+
+ update_prop_from_entry (editor, editor->priv->keywords_entry,
+ EPHY_NODE_BMK_PROP_KEYWORDS);
+}
+
+static GtkWidget *
+build_editing_table (EphyBookmarksEditor *editor)
+{
+ GtkWidget *table, *label, *entry;
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Title:</b>"));
+ gtk_widget_show (label);
+ entry = gtk_entry_new ();
+ editor->priv->title_entry = entry;
+ gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (title_entry_changed_cb),
+ editor);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Keywords:</b>"));
+ gtk_widget_show (label);
+ entry = ephy_keywords_entry_new ();
+ ephy_keywords_entry_set_bookmarks (EPHY_KEYWORDS_ENTRY (entry),
+ editor->priv->bookmarks);
+ editor->priv->keywords_entry = entry;
+ gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2);
+ g_signal_connect (G_OBJECT (entry), "keywords_changed",
+ G_CALLBACK (keywords_changed_cb),
+ editor);
+
+ return table;
+}
+
+static void
+bookmarks_filter (EphyBookmarksEditor *editor,
+ EphyNode *keyword)
+{
+ ephy_node_filter_empty (editor->priv->bookmarks_filter);
+ ephy_node_filter_add_expression (editor->priv->bookmarks_filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT,
+ keyword),
+ 0);
+ ephy_node_filter_done_changing (editor->priv->bookmarks_filter);
+}
+
+static void
+keyword_node_selected_cb (EphyNodeView *view,
+ EphyNode *node,
+ EphyBookmarksEditor *editor)
+{
+ if (node == NULL)
+ {
+ ephy_node_view_select_node
+ (editor->priv->key_view,
+ ephy_bookmarks_get_bookmarks
+ (editor->priv->bookmarks));
+ }
+ else
+ {
+ bookmarks_filter (editor, node);
+ }
+}
+
+static void
+search_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor)
+{
+ char *search_text;
+
+ search_text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+
+ GDK_THREADS_ENTER ();
+
+ ephy_node_filter_empty (editor->priv->bookmarks_filter);
+ ephy_node_filter_add_expression (editor->priv->bookmarks_filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_BMK_PROP_TITLE,
+ search_text),
+ 0);
+ ephy_node_filter_add_expression (editor->priv->bookmarks_filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_BMK_PROP_KEYWORDS,
+ search_text),
+ 0);
+ ephy_node_filter_done_changing (editor->priv->bookmarks_filter);
+
+ GDK_THREADS_LEAVE ();
+
+ g_free (search_text);
+}
+
+static GtkWidget *
+build_search_box (EphyBookmarksEditor *editor)
+{
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *entry;
+
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (box);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Search:</b>"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (box),
+ label, FALSE, TRUE, 0);
+
+ entry = gtk_entry_new ();
+ editor->priv->search_entry = entry;
+ gtk_widget_show (entry);
+ gtk_box_pack_start (GTK_BOX (box),
+ entry, TRUE, TRUE, 0);
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (search_entry_changed_cb),
+ editor);
+ return box;
+}
+
+static void
+ephy_bookmarks_editor_construct (EphyBookmarksEditor *editor)
+{
+ GtkWidget *hbox, *vbox;
+ EphyNodeView *bm_view, *key_view;
+ EphyNode *node;
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (editor), 6);
+ gtk_widget_set_size_request (GTK_WIDGET (editor), 500, 400);
+ g_signal_connect (G_OBJECT (editor),
+ "response",
+ G_CALLBACK (ephy_bookmarks_editor_response_cb),
+ editor);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox),
+ hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ g_assert (editor->priv->bookmarks);
+
+ node = ephy_bookmarks_get_keywords (editor->priv->bookmarks);
+ key_view = ephy_node_view_new (node, NULL);
+ ephy_node_view_set_browse_mode (key_view);
+ ephy_node_view_add_column (key_view, _("Keywords"),
+ EPHY_TREE_MODEL_NODE_COL_KEYWORD, FALSE);
+ gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (key_view), FALSE, TRUE, 0);
+ gtk_widget_set_size_request (GTK_WIDGET (key_view), 120, -1);
+ gtk_widget_show (GTK_WIDGET (key_view));
+ editor->priv->key_view = key_view;
+ g_signal_connect (G_OBJECT (key_view),
+ "node_selected",
+ G_CALLBACK (keyword_node_selected_cb),
+ editor);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ build_search_box (editor),
+ FALSE, FALSE, 0);
+
+ node = ephy_bookmarks_get_bookmarks (editor->priv->bookmarks);
+ editor->priv->bookmarks_filter = ephy_node_filter_new ();
+ bm_view = ephy_node_view_new (node, editor->priv->bookmarks_filter);
+ ephy_node_view_enable_drag_source (bm_view);
+ ephy_node_view_add_column (bm_view, _("Title"),
+ EPHY_TREE_MODEL_NODE_COL_BOOKMARK, TRUE);
+ ephy_node_view_add_column (bm_view, _("Location"),
+ EPHY_TREE_MODEL_NODE_COL_LOCATION, TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (bm_view), TRUE, TRUE, 0);
+ gtk_widget_show (GTK_WIDGET (bm_view));
+ editor->priv->bm_view = bm_view;
+ g_signal_connect (G_OBJECT (bm_view),
+ "node_activated",
+ G_CALLBACK (ephy_bookmarks_editor_node_activated_cb),
+ editor);
+ g_signal_connect (G_OBJECT (bm_view),
+ "node_selected",
+ G_CALLBACK (ephy_bookmarks_editor_node_selected_cb),
+ editor);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ build_editing_table (editor),
+ FALSE, FALSE, 0);
+
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_REMOVE,
+ RESPONSE_REMOVE);
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_CLOSE);
+}
+
+GtkWidget *
+ephy_bookmarks_editor_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent)
+{
+ EphyBookmarksEditor *editor;
+
+ g_assert (bookmarks != NULL);
+
+ editor = EPHY_BOOKMARKS_EDITOR (g_object_new
+ (EPHY_TYPE_BOOKMARKS_EDITOR,
+ "bookmarks", bookmarks,
+ NULL));
+
+ if (parent)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
+ }
+
+ ephy_bookmarks_editor_construct (editor);
+
+ return GTK_WIDGET (editor);
+}
+
+static void
+ephy_bookmarks_editor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_BOOKMARKS:
+ editor->priv->bookmarks = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_bookmarks_editor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_BOOKMARKS:
+ g_value_set_object (value, editor->priv->bookmarks);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_bookmarks_editor_init (EphyBookmarksEditor *editor)
+{
+ editor->priv = g_new0 (EphyBookmarksEditorPrivate, 1);
+}
diff --git a/src/bookmarks/ephy-bookmarks-editor.h b/src/bookmarks/ephy-bookmarks-editor.h
new file mode 100644
index 000000000..f79dfa673
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks-editor.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_BOOKMARKS_EDITOR_H
+#define EPHY_BOOKMARKS_EDITOR_H
+
+#include <gtk/gtkdialog.h>
+
+#include "ephy-node-view.h"
+#include "ephy-bookmarks.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_BOOKMARKS_EDITOR (ephy_bookmarks_editor_get_type ())
+#define EPHY_BOOKMARKS_EDITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditor))
+#define EPHY_BOOKMARKS_EDITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditorClass))
+#define EPHY_IS_BOOKMARKS_EDITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_BOOKMARKS_EDITOR))
+#define EPHY_IS_BOOKMARKS_EDITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_BOOKMARKS_EDITOR))
+#define EPHY_BOOKMARKS_EDITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditorClass))
+
+typedef struct EphyBookmarksEditorPrivate EphyBookmarksEditorPrivate;
+
+typedef struct
+{
+ GtkDialog parent;
+
+ EphyBookmarksEditorPrivate *priv;
+} EphyBookmarksEditor;
+
+typedef struct
+{
+ GtkDialogClass parent;
+} EphyBookmarksEditorClass;
+
+GType ephy_bookmarks_editor_get_type (void);
+
+GtkWidget *ephy_bookmarks_editor_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* EPHY_BOOKMARKS_EDITOR_H */
diff --git a/src/bookmarks/ephy-bookmarks.c b/src/bookmarks/ephy-bookmarks.c
new file mode 100644
index 000000000..e27a30496
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks.c
@@ -0,0 +1,988 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-bookmarks.h"
+#include "ephy-file-helpers.h"
+#include "ephy-shell.h"
+#include "ephy-history.h"
+
+#include <string.h>
+#include <libgnome/gnome-i18n.h>
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define EPHY_BOOKMARKS_XML_VERSION "0.1"
+
+#define MAX_FAVORITES_NUM 10
+
+struct EphyBookmarksPrivate
+{
+ char *xml_file;
+ EphyNode *bookmarks;
+ EphyNode *keywords;
+ EphyNode *favorites;
+ EphyNode *lower_fav;
+ double lower_score;
+ GHashTable *bookmarks_hash;
+ GStaticRWLock *bookmarks_hash_lock;
+ GHashTable *favorites_hash;
+ GStaticRWLock *favorites_hash_lock;
+ GHashTable *keywords_hash;
+ GStaticRWLock *keywords_hash_lock;
+};
+
+static void
+ephy_bookmarks_class_init (EphyBookmarksClass *klass);
+static void
+ephy_bookmarks_init (EphyBookmarks *tab);
+static void
+ephy_bookmarks_finalize (GObject *object);
+static void
+ephy_bookmarks_autocompletion_source_init (EphyAutocompletionSourceIface *iface);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_bookmarks_get_type (void)
+{
+ static GType ephy_bookmarks_type = 0;
+
+ if (ephy_bookmarks_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyBookmarksClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_bookmarks_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyBookmarks),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_bookmarks_init
+ };
+
+ static const GInterfaceInfo autocompletion_source_info =
+ {
+ (GInterfaceInitFunc) ephy_bookmarks_autocompletion_source_init,
+ NULL,
+ NULL
+ };
+
+ ephy_bookmarks_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyBookmarks",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_bookmarks_type,
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE,
+ &autocompletion_source_info);
+ }
+
+ return ephy_bookmarks_type;
+}
+
+static void
+ephy_bookmarks_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key)
+{
+ /* nothing to do here */
+}
+
+static void
+ephy_bookmarks_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *current_text,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data)
+{
+ GPtrArray *children;
+ int i;
+ EphyBookmarks *eb = EPHY_BOOKMARKS (source);
+
+ children = ephy_node_get_children (eb->priv->bookmarks);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+ const char *url, *smart_url, *title, *keywords;
+ char *item;
+
+ kid = g_ptr_array_index (children, i);
+ url = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_LOCATION);
+ smart_url = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_SMART_LOCATION);
+ title = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_TITLE);
+ keywords = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_KEYWORDS);
+ item = g_strconcat (title, keywords, NULL);
+
+ if (smart_url == NULL ||
+ g_utf8_strlen (smart_url, -1) == 0)
+ {
+ smart_url = NULL;
+ }
+
+ func (source,
+ smart_url ? NULL : item,
+ title,
+ smart_url ? smart_url : url,
+ (smart_url != NULL),
+ TRUE, 0, data);
+
+ g_free (item);
+ }
+ ephy_node_thaw (eb->priv->bookmarks);
+}
+
+static void
+ephy_bookmarks_emit_data_changed (EphyBookmarks *eb)
+{
+ g_signal_emit_by_name (eb, "data-changed");
+}
+
+static void
+ephy_bookmarks_autocompletion_source_init (EphyAutocompletionSourceIface *iface)
+{
+ iface->foreach = ephy_bookmarks_autocompletion_source_foreach;
+ iface->set_basic_key = ephy_bookmarks_autocompletion_source_set_basic_key;
+}
+
+static void
+ephy_bookmarks_class_init (EphyBookmarksClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_bookmarks_finalize;
+}
+
+static gboolean
+ephy_bookmarks_clean_empty_keywords (EphyBookmarks *eb)
+{
+ GPtrArray *children;
+ int i;
+
+ children = ephy_node_get_children (eb->priv->keywords);
+ ephy_node_thaw (eb->priv->keywords);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ if (ephy_node_get_n_children (kid) == 0)
+ {
+ DEBUG_MSG (("Remove empty keyword: %s\n",
+ ephy_node_get_property_string (kid,
+ EPHY_NODE_KEYWORD_PROP_NAME)));
+ ephy_node_unref (kid);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_bookmarks_load (EphyBookmarks *eb)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, child;
+ char *tmp;
+
+ if (g_file_test (eb->priv->xml_file, G_FILE_TEST_EXISTS) == FALSE)
+ return;
+
+ doc = xmlParseFile (eb->priv->xml_file);
+ g_assert (doc != NULL);
+
+ root = xmlDocGetRootElement (doc);
+
+ tmp = xmlGetProp (root, "version");
+ g_assert (tmp != NULL && strcmp (tmp, EPHY_BOOKMARKS_XML_VERSION) == 0);
+ g_free (tmp);
+
+ for (child = root->children; child != NULL; child = child->next)
+ {
+ EphyNode *node;
+
+ node = ephy_node_new_from_xml (child);
+ }
+
+ xmlFreeDoc (doc);
+}
+
+static void
+ephy_bookmarks_save (EphyBookmarks *eb)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ GPtrArray *children;
+ int i;
+
+ DEBUG_MSG (("Saving bookmarks\n"));
+
+ /* save nodes to xml */
+ xmlIndentTreeOutput = TRUE;
+ doc = xmlNewDoc ("1.0");
+
+ root = xmlNewDocNode (doc, NULL, "ephy_bookmarks", NULL);
+ xmlSetProp (root, "version", EPHY_BOOKMARKS_XML_VERSION);
+ xmlDocSetRootElement (doc, root);
+
+ children = ephy_node_get_children (eb->priv->keywords);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ if (kid != eb->priv->bookmarks)
+ {
+ ephy_node_save_to_xml (kid, root);
+ }
+ }
+ ephy_node_thaw (eb->priv->keywords);
+
+ children = ephy_node_get_children (eb->priv->bookmarks);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ ephy_node_save_to_xml (kid, root);
+ }
+ ephy_node_thaw (eb->priv->bookmarks);
+
+ xmlSaveFormatFile (eb->priv->xml_file, doc, 1);
+}
+
+static double
+get_history_item_score (EphyHistory *eh, const char *page)
+{
+ return ephy_history_get_page_visits (eh, page);
+}
+
+static EphyNode *
+compute_lower_fav (EphyNode *favorites, double *score)
+{
+ GPtrArray *children;
+ int i;
+ EphyEmbedShell *embed_shell;
+ EphyHistory *history;
+ EphyNode *result = NULL;
+
+ embed_shell = ephy_shell_get_embed_shell (ephy_shell);
+ history = ephy_embed_shell_get_global_history (embed_shell);
+
+ *score = DBL_MAX;
+ children = ephy_node_get_children (favorites);
+ for (i = 0; i < children->len; i++)
+ {
+ const char *url;
+ EphyNode *child;
+ double item_score;
+
+ child = g_ptr_array_index (children, i);
+ url = ephy_node_get_property_string
+ (child, EPHY_NODE_BMK_PROP_LOCATION);
+ item_score = get_history_item_score (history, url);
+ if (*score > item_score)
+ {
+ *score = item_score;
+ result = child;
+ }
+ }
+ ephy_node_thaw (favorites);
+
+ if (result == NULL) *score = 0;
+
+ return result;
+}
+
+static void
+ephy_bookmarks_update_favorites (EphyBookmarks *eb)
+{
+ eb->priv->lower_fav = compute_lower_fav (eb->priv->favorites,
+ &eb->priv->lower_score);
+}
+
+static gboolean
+add_to_favorites (EphyBookmarks *eb, EphyNode *node, EphyHistory *eh)
+{
+ const char *url;
+ EphyNode *fav_node;
+ gboolean full_menu;
+ double score;
+
+ url = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION);
+ g_static_rw_lock_reader_lock (eb->priv->favorites_hash_lock);
+ fav_node = g_hash_table_lookup (eb->priv->favorites_hash, url);
+ g_static_rw_lock_reader_unlock (eb->priv->favorites_hash_lock);
+ if (fav_node) return FALSE;
+
+ score = get_history_item_score (eh, url);
+ full_menu = ephy_node_get_n_children (eb->priv->favorites)
+ > MAX_FAVORITES_NUM;
+ if (full_menu && score < eb->priv->lower_score) return FALSE;
+
+ if (eb->priv->lower_fav && full_menu)
+ {
+ ephy_node_remove_child (eb->priv->favorites,
+ eb->priv->lower_fav);
+ }
+
+ ephy_node_add_child (eb->priv->favorites, node);
+ ephy_bookmarks_update_favorites (eb);
+
+ return TRUE;
+}
+
+static void
+update_favorites_menus ()
+{
+ Session *session;
+ GList *l;
+
+ session = ephy_shell_get_session (ephy_shell);
+ l = session_get_windows (session);
+
+ for (; l != NULL; l = l->next)
+ {
+ EphyWindow *window = EPHY_WINDOW (l->data);
+
+ ephy_window_update_control (window, FavoritesControl);
+ }
+}
+
+static void
+history_site_visited_cb (EphyHistory *gh, const char *url, EphyBookmarks *eb)
+{
+ EphyNode *node;
+
+ g_static_rw_lock_reader_lock (eb->priv->bookmarks_hash_lock);
+ node = g_hash_table_lookup (eb->priv->bookmarks_hash, url);
+ g_static_rw_lock_reader_unlock (eb->priv->bookmarks_hash_lock);
+ if (!node) return;
+
+ if (add_to_favorites (eb, node, gh))
+ {
+ update_favorites_menus ();
+ }
+}
+
+static void
+ephy_setup_history_notifiers (EphyBookmarks *eb)
+{
+ EphyEmbedShell *embed_shell;
+ EphyHistory *history;
+
+ embed_shell = ephy_shell_get_embed_shell (ephy_shell);
+ history = ephy_embed_shell_get_global_history (embed_shell);
+
+ g_signal_connect (history, "visited",
+ G_CALLBACK (history_site_visited_cb), eb);
+}
+
+static void
+keywords_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->keywords_hash_lock);
+
+ g_hash_table_insert (eb->priv->keywords_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_KEYWORD_PROP_NAME),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->keywords_hash_lock);
+}
+
+static void
+keywords_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->keywords_hash_lock);
+
+ g_hash_table_remove (eb->priv->keywords_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_KEYWORD_PROP_NAME));
+
+ g_static_rw_lock_writer_unlock (eb->priv->keywords_hash_lock);
+}
+
+static void
+favorites_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->favorites_hash_lock);
+
+ g_hash_table_insert (eb->priv->favorites_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->favorites_hash_lock);
+}
+
+static void
+favorites_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->favorites_hash_lock);
+
+ g_hash_table_remove (eb->priv->favorites_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION));
+
+ g_static_rw_lock_writer_unlock (eb->priv->favorites_hash_lock);
+}
+
+static void
+bookmarks_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->bookmarks_hash_lock);
+
+ g_hash_table_insert (eb->priv->bookmarks_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->bookmarks_hash_lock);
+}
+
+static void
+bookmarks_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ ephy_bookmarks_emit_data_changed (eb);
+ g_idle_add ((GSourceFunc)ephy_bookmarks_clean_empty_keywords, eb);
+
+ g_static_rw_lock_writer_lock (eb->priv->bookmarks_hash_lock);
+
+ g_hash_table_remove (eb->priv->bookmarks_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION));
+
+ g_static_rw_lock_writer_unlock (eb->priv->bookmarks_hash_lock);
+}
+
+static void
+ephy_bookmarks_init (EphyBookmarks *eb)
+{
+ GValue value = { 0, };
+
+ eb->priv = g_new0 (EphyBookmarksPrivate, 1);
+
+ eb->priv->xml_file = g_build_filename (ephy_dot_dir (),
+ "bookmarks.xml",
+ NULL);
+
+ eb->priv->bookmarks_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->bookmarks_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->bookmarks_hash_lock);
+
+ eb->priv->keywords_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->keywords_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->keywords_hash_lock);
+
+ eb->priv->favorites_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->favorites_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->favorites_hash_lock);
+
+ /* Bookmarks */
+ eb->priv->bookmarks = ephy_node_new ();
+ ephy_node_ref (eb->priv->bookmarks);
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, _("All"));
+ ephy_node_set_property (eb->priv->bookmarks,
+ EPHY_NODE_KEYWORD_PROP_NAME,
+ &value);
+ g_value_unset (&value);
+ g_signal_connect_object (G_OBJECT (eb->priv->bookmarks),
+ "child_added",
+ G_CALLBACK (bookmarks_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->bookmarks),
+ "child_removed",
+ G_CALLBACK (bookmarks_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ /* Keywords */
+ eb->priv->keywords = ephy_node_new ();
+ ephy_node_ref (eb->priv->keywords);
+
+ ephy_node_add_child (eb->priv->keywords,
+ eb->priv->bookmarks);
+ g_signal_connect_object (G_OBJECT (eb->priv->keywords),
+ "child_added",
+ G_CALLBACK (keywords_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->keywords),
+ "child_removed",
+ G_CALLBACK (keywords_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ eb->priv->favorites = ephy_node_new ();
+ ephy_node_ref (eb->priv->favorites);
+ g_signal_connect_object (G_OBJECT (eb->priv->favorites),
+ "child_added",
+ G_CALLBACK (favorites_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->favorites),
+ "child_removed",
+ G_CALLBACK (favorites_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ ephy_bookmarks_load (eb);
+ ephy_bookmarks_emit_data_changed (eb);
+
+ ephy_setup_history_notifiers (eb);
+ ephy_bookmarks_update_favorites (eb);
+}
+
+static void
+ephy_bookmarks_finalize (GObject *object)
+{
+ EphyBookmarks *eb;
+
+ g_return_if_fail (IS_EPHY_BOOKMARKS (object));
+
+ eb = EPHY_BOOKMARKS (object);
+
+ g_return_if_fail (eb->priv != NULL);
+
+ ephy_bookmarks_save (eb);
+
+ ephy_node_unref (eb->priv->bookmarks);
+ ephy_node_unref (eb->priv->keywords);
+ ephy_node_unref (eb->priv->favorites);
+
+ g_hash_table_destroy (eb->priv->bookmarks_hash);
+ g_static_rw_lock_free (eb->priv->bookmarks_hash_lock);
+ g_hash_table_destroy (eb->priv->favorites_hash);
+ g_static_rw_lock_free (eb->priv->favorites_hash_lock);
+ g_hash_table_destroy (eb->priv->keywords_hash);
+ g_static_rw_lock_free (eb->priv->keywords_hash_lock);
+
+ g_free (eb->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyBookmarks *
+ephy_bookmarks_new ()
+{
+ EphyBookmarks *tab;
+
+ tab = EPHY_BOOKMARKS (g_object_new (EPHY_BOOKMARKS_TYPE, NULL));
+
+ return tab;
+}
+
+EphyNode *
+ephy_bookmarks_add (EphyBookmarks *eb,
+ const char *title,
+ const char *url,
+ const char *smart_url,
+ const char *keywords)
+{
+ EphyNode *bm;
+ GValue value = { 0, };
+
+ bm = ephy_node_new ();
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, title);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_TITLE,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, url);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_LOCATION,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, smart_url);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_SMART_LOCATION,
+ &value);
+ g_value_unset (&value);
+
+ ephy_bookmarks_update_keywords (eb, keywords, bm);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, keywords);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_KEYWORDS,
+ &value);
+ g_value_unset (&value);
+
+ ephy_node_add_child (eb->priv->bookmarks, bm);
+
+ ephy_bookmarks_emit_data_changed (eb);
+
+ return bm;
+}
+
+static gchar *
+options_skip_spaces (const gchar *str)
+{
+ const gchar *ret = str;
+ while (*ret && g_ascii_isspace (*ret))
+ {
+ ++ret;
+ }
+ return (gchar *) ret;
+}
+
+static char *
+options_find_value_end (const gchar *value_start)
+{
+ const gchar *value_end;
+ if (*value_start == '"')
+ {
+ for (value_end = value_start + 1;
+ *value_end && (*value_end != '"' || *(value_end - 1) == '\\');
+ ++value_end) ;
+ }
+ else
+ {
+ for (value_end = value_start;
+ *value_end && ! (g_ascii_isspace (*value_end)
+ || *value_end == ','
+ || *value_end == ';');
+ ++value_end) ;
+ }
+ return (gchar *) value_end;
+}
+
+static char *
+options_find_next_option (const char *current)
+{
+ const gchar *value_start;
+ const gchar *value_end;
+ const gchar *ret;
+ value_start = strchr (current, '=');
+ if (!value_start) return NULL;
+ value_start = options_skip_spaces (value_start + 1);
+ value_end = options_find_value_end (value_start);
+ if (! (*value_end)) return NULL;
+ for (ret = value_end + 1;
+ *ret && (g_ascii_isspace (*ret)
+ || *ret == ','
+ || *ret == ';');
+ ++ret);
+ return (char *) ret;
+}
+
+/**
+ * Very simple parser for option strings in the
+ * form a=b,c=d,e="f g",...
+ */
+static gchar *
+smart_url_options_get (const gchar *options, const gchar *option)
+{
+ gchar *ret = NULL;
+ gsize optionlen = strlen (option);
+ const gchar *current = options_skip_spaces (options);
+
+ while (current)
+ {
+ if (!strncmp (option, current, optionlen))
+ {
+ if (g_ascii_isspace (*(current + optionlen)) || *(current + optionlen) == '=')
+ {
+ const gchar *value_start;
+ const gchar *value_end;
+ value_start = strchr (current + optionlen, '=');
+ if (!value_start) continue;
+ value_start = options_skip_spaces (value_start + 1);
+ value_end = options_find_value_end (value_start);
+ if (*value_start == '"') value_start++;
+ if (value_end >= value_start)
+ {
+ ret = g_strndup (value_start, value_end - value_start);
+ break;
+ }
+ }
+ }
+ current = options_find_next_option (current);
+ }
+
+ return ret;
+}
+
+static char *
+get_smarturl_only (const char *smarturl)
+{
+ const gchar *openbrace;
+ const gchar *closebrace;
+ const gchar *c;
+
+ openbrace = strchr (smarturl, '{');
+ if (!openbrace) return g_strdup (smarturl);
+ for (c = smarturl; c < openbrace; ++c)
+ {
+ if (!strchr (" \t\n", *c)) return g_strdup (smarturl);
+ }
+
+ closebrace = strchr (openbrace + 1, '}');
+ if (!closebrace) return g_strdup (smarturl);
+
+ return g_strdup (closebrace + 1);
+}
+
+char *
+ephy_bookmarks_solve_smart_url (EphyBookmarks *eb,
+ const char *smart_url,
+ const char *content)
+{
+ gchar *ret;
+ GString *s;
+ gchar *t1;
+ gchar *t2;
+ gchar *encoding;
+ gchar *smarturl_only;
+ gchar *arg;
+
+ g_return_val_if_fail (content != NULL, NULL);
+
+ smarturl_only = get_smarturl_only (smart_url);
+
+ s = g_string_new ("");
+
+ encoding = smart_url_options_get (smart_url, "encoding");
+ if (!encoding)
+ {
+ encoding = g_strdup ("UTF-8");
+ }
+
+ arg = g_convert (content, strlen (content),
+ encoding, "UTF-8", NULL, NULL, NULL);
+
+ t1 = smarturl_only;
+ t2 = strstr (t1, "%s");
+ g_return_val_if_fail (t2 != NULL, NULL);
+ g_string_append_len (s, t1, t2 - t1);
+ g_string_append (s, arg);
+ t1 = t2 + 2;
+ g_string_append (s, t1);
+ ret = s->str;
+ g_string_free (s, FALSE);
+
+ g_free (arg);
+ g_free (encoding);
+ g_free (smarturl_only);
+
+ return ret;
+}
+
+EphyNode *
+ephy_bookmarks_add_keyword (EphyBookmarks *eb,
+ const char *name)
+{
+ EphyNode *key;
+ GValue value = { 0, };
+
+ key = ephy_node_new ();
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, name);
+ ephy_node_set_property (key, EPHY_NODE_KEYWORD_PROP_NAME,
+ &value);
+ g_value_unset (&value);
+
+ ephy_node_add_child (eb->priv->keywords, key);
+
+ return key;
+}
+
+EphyNode *
+ephy_bookmarks_find_keyword (EphyBookmarks *eb,
+ const char *name,
+ gboolean partial_match)
+{
+ EphyNode *node;
+
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (!partial_match)
+ {
+ g_static_rw_lock_reader_lock (eb->priv->keywords_hash_lock);
+ node = g_hash_table_lookup (eb->priv->keywords_hash, name);
+ g_static_rw_lock_reader_unlock (eb->priv->keywords_hash_lock);
+ }
+ else
+ {
+ GPtrArray *children;
+ int i;
+
+ if (g_utf8_strlen (name, -1) == 0)
+ {
+ DEBUG_MSG (("Empty name, no keyword matches.\n"));
+ return NULL;
+ }
+
+ children = ephy_node_get_children (eb->priv->keywords);
+ node = NULL;
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+ const char *key;
+
+ kid = g_ptr_array_index (children, i);
+ key = ephy_node_get_property_string (kid, EPHY_NODE_KEYWORD_PROP_NAME);
+
+ if (g_str_has_prefix (key, name) > 0)
+ {
+ node = kid;
+ }
+ }
+ ephy_node_thaw (eb->priv->keywords);
+ }
+
+ return node;
+}
+
+void
+ephy_bookmarks_set_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark)
+{
+ ephy_node_add_child (keyword, bookmark);
+}
+
+void
+ephy_bookmarks_unset_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark)
+{
+ ephy_node_remove_child (keyword, bookmark);
+ ephy_bookmarks_clean_empty_keywords (eb);
+}
+
+static GList *
+diff_keywords (char **ks1, char **ks2)
+{
+ GList *result = NULL;
+ int i, j;
+
+ for (i = 0; ks1 != NULL && ks1[i] != NULL; i++)
+ {
+ gboolean found = FALSE;
+
+ DEBUG_MSG (("Diff keywords, keyword:\"%s\"\n", ks1[i]));
+
+ for (j = 0; ks2 != NULL && ks2[j] != NULL; j++)
+ {
+ if (strcmp (ks1[i], ks2[j]) == 0)
+ {
+ found = TRUE;
+ }
+ }
+
+ if (!found && g_utf8_strlen (ks1[i], -1) > 0)
+ {
+ result = g_list_append (result, ks1[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+ephy_bookmarks_update_keywords (EphyBookmarks *eb,
+ const char *keywords,
+ EphyNode *node)
+{
+ const char *prop;
+ char **ks, **old_ks = NULL;
+ GList *diffs, *l;
+ EphyNode *keyword;
+
+ prop = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_KEYWORDS);
+ ks = g_strsplit (keywords, " ", 10);
+ if (prop != NULL)
+ {
+ old_ks = g_strsplit (prop, " ", 10);
+ }
+
+ diffs = diff_keywords (ks, old_ks);
+ for (l = diffs; l != NULL; l = l->next)
+ {
+ char *word = (char *)l->data;
+
+ keyword = ephy_bookmarks_find_keyword
+ (eb, word, FALSE);
+
+ if (!keyword)
+ {
+ keyword = ephy_bookmarks_add_keyword
+ (eb, word);
+ }
+
+ ephy_bookmarks_set_keyword (eb, keyword, node);
+ }
+ g_list_free (diffs);
+
+ diffs = diff_keywords (old_ks, ks);
+ for (l = diffs; l != NULL; l = l->next)
+ {
+ keyword = ephy_bookmarks_find_keyword (eb,
+ (char *)l->data, FALSE);
+ g_return_if_fail (keyword != NULL);
+
+ ephy_bookmarks_unset_keyword (eb, keyword, node);
+ }
+ g_list_free (diffs);
+
+ g_strfreev (ks);
+ g_strfreev (old_ks);
+}
+
+EphyNode *
+ephy_bookmarks_get_keywords (EphyBookmarks *eb)
+{
+ return eb->priv->keywords;
+}
+
+EphyNode *
+ephy_bookmarks_get_bookmarks (EphyBookmarks *eb)
+{
+ return eb->priv->bookmarks;
+}
+
+EphyNode *
+ephy_bookmarks_get_favorites (EphyBookmarks *eb)
+{
+ return eb->priv->favorites;
+}
+
diff --git a/src/bookmarks/ephy-bookmarks.h b/src/bookmarks/ephy-bookmarks.h
new file mode 100644
index 000000000..e355950c4
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_BOOKMARKS_H
+#define EPHY_BOOKMARKS_H
+
+#include <glib-object.h>
+
+#include "ephy-node.h"
+
+G_BEGIN_DECLS
+
+typedef struct EphyBookmarksClass EphyBookmarksClass;
+
+#define EPHY_BOOKMARKS_TYPE (ephy_bookmarks_get_type ())
+#define EPHY_BOOKMARKS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_BOOKMARKS_TYPE, EphyBookmarks))
+#define EPHY_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_BOOKMARKS_TYPE, EphyBookmarksClass))
+#define IS_EPHY_BOOKMARKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_BOOKMARKS_TYPE))
+#define IS_EPHY_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_BOOKMARKS_TYPE))
+
+typedef struct EphyBookmarks EphyBookmarks;
+typedef struct EphyBookmarksPrivate EphyBookmarksPrivate;
+
+enum
+{
+ EPHY_NODE_BMK_PROP_TITLE = 2,
+ EPHY_NODE_BMK_PROP_LOCATION = 3,
+ EPHY_NODE_BMK_PROP_KEYWORDS = 4,
+ EPHY_NODE_KEYWORD_PROP_NAME = 5,
+ EPHY_NODE_BMK_PROP_SMART_LOCATION = 6
+};
+
+struct EphyBookmarks
+{
+ GObject parent;
+ EphyBookmarksPrivate *priv;
+};
+
+struct EphyBookmarksClass
+{
+ GObjectClass parent_class;
+};
+
+GType ephy_bookmarks_get_type (void);
+
+EphyBookmarks *ephy_bookmarks_new (void);
+
+/* Bookmarks */
+
+EphyNode *ephy_bookmarks_add (EphyBookmarks *eb,
+ const char *title,
+ const char *url,
+ const char *smart_url,
+ const char *keywords);
+
+char *ephy_bookmarks_solve_smart_url (EphyBookmarks *eb,
+ const char *smart_url,
+ const char *content);
+
+/* Keywords */
+
+EphyNode *ephy_bookmarks_add_keyword (EphyBookmarks *eb,
+ const char *name);
+
+EphyNode *ephy_bookmarks_find_keyword (EphyBookmarks *eb,
+ const char *name,
+ gboolean partial_match);
+
+void ephy_bookmarks_set_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark);
+
+void ephy_bookmarks_unset_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark);
+
+void ephy_bookmarks_update_keywords (EphyBookmarks *eb,
+ const char *keywords,
+ EphyNode *bookmark_node);
+
+/* Favorites */
+
+EphyNode *ephy_bookmarks_get_favorites (EphyBookmarks *eb);
+
+/* Root */
+
+EphyNode *ephy_bookmarks_get_keywords (EphyBookmarks *eb);
+
+EphyNode *ephy_bookmarks_get_bookmarks (EphyBookmarks *eb);
+
+G_END_DECLS
+
+#endif
diff --git a/src/bookmarks/ephy-keywords-entry.c b/src/bookmarks/ephy-keywords-entry.c
new file mode 100644
index 000000000..94d6c93a9
--- /dev/null
+++ b/src/bookmarks/ephy-keywords-entry.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-keywords-entry.h"
+#include "ephy-marshal.h"
+#include "ephy-gobject-misc.h"
+
+#include <gdk/gdkkeysyms.h>
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+/**
+ * Private data
+ */
+struct _EphyKeywordsEntryPrivate
+{
+ EphyBookmarks *bookmarks;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_keywords_entry_class_init (EphyKeywordsEntryClass *klass);
+static void ephy_keywords_entry_init (EphyKeywordsEntry *w);
+static void ephy_keywords_entry_finalize_impl (GObject *o);
+static gint ephy_keywords_entry_key_press (GtkWidget *widget,
+ GdkEventKey *event);
+
+enum
+{
+ KEYWORDS_CHANGED,
+ LAST_SIGNAL
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint keywords_entry_signals[LAST_SIGNAL] = { 0 };
+
+MAKE_GET_TYPE (ephy_keywords_entry, "EphyKeywordsEntry", EphyKeywordsEntry,
+ ephy_keywords_entry_class_init,
+ ephy_keywords_entry_init, GTK_TYPE_ENTRY);
+
+static void
+ephy_keywords_entry_class_init (EphyKeywordsEntryClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ widget_class = (GtkWidgetClass*) class;
+
+ gobject_class->finalize = ephy_keywords_entry_finalize_impl;
+
+ widget_class->key_press_event = ephy_keywords_entry_key_press;
+
+ keywords_entry_signals[KEYWORDS_CHANGED] =
+ g_signal_new ("keywords_changed",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyKeywordsEntryClass, keywords_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+try_to_expand_keyword (GtkEditable *editable)
+{
+ char *entry_text;
+ char *user_text;
+ const char *expand_text;
+ char *insert_text;
+ int user_text_length;
+ int expand_text_length;
+ int keyword_offset = 0;
+ int tmp;
+ EphyKeywordsEntry *entry = EPHY_KEYWORDS_ENTRY (editable);
+ EphyNode *node;
+
+ entry_text = gtk_editable_get_chars (editable, 0, -1);
+ g_return_if_fail (entry_text != NULL);
+
+ DEBUG_MSG (("Entry text \"%s\"\n", entry_text));
+
+ user_text = g_utf8_strrchr (entry_text, -1, ' ');
+
+ if (user_text)
+ {
+ user_text = g_utf8_find_next_char (user_text, NULL);
+ keyword_offset = g_utf8_pointer_to_offset
+ (entry_text, user_text);
+ }
+ else
+ {
+ user_text = entry_text;
+ }
+
+ DEBUG_MSG (("User text \"%s\"\n", user_text));
+
+ node = ephy_bookmarks_find_keyword (entry->priv->bookmarks,
+ user_text, TRUE);
+ if (node)
+ {
+ expand_text = ephy_node_get_property_string
+ (node, EPHY_NODE_KEYWORD_PROP_NAME);
+
+ DEBUG_MSG (("Expand text %s\n", expand_text));
+
+ expand_text_length = g_utf8_strlen (expand_text, -1);
+ user_text_length = g_utf8_strlen (user_text, -1);
+
+ insert_text = g_utf8_offset_to_pointer (expand_text, user_text_length);
+ gtk_editable_insert_text (editable,
+ insert_text,
+ g_utf8_strlen (insert_text, -1),
+ &tmp);
+ gtk_editable_select_region (editable, user_text_length + keyword_offset, -1);
+ }
+ else
+ {
+ DEBUG_MSG (("No expansion.\n"));
+ }
+
+ g_free (entry_text);
+}
+
+/* Until we have a more elegant solution, this is how we figure out if
+ * the GtkEntry inserted characters, assuming that the return value is
+ * TRUE indicating that the GtkEntry consumed the key event for some
+ * reason. This is a clone of code from GtkEntry.
+ */
+static gboolean
+entry_would_have_inserted_characters (const GdkEventKey *event)
+{
+ switch (event->keyval) {
+ case GDK_BackSpace:
+ case GDK_Clear:
+ case GDK_Insert:
+ case GDK_Delete:
+ case GDK_Home:
+ case GDK_End:
+ case GDK_Left:
+ case GDK_Right:
+ case GDK_Return:
+ return FALSE;
+ default:
+ if (event->keyval >= 0x20 && event->keyval <= 0xFF) {
+ if ((event->state & GDK_CONTROL_MASK) != 0) {
+ return FALSE;
+ }
+ if ((event->state & GDK_MOD1_MASK) != 0) {
+ return FALSE;
+ }
+ }
+ return event->length > 0;
+ }
+}
+
+static int
+get_editable_number_of_chars (GtkEditable *editable)
+{
+ char *text;
+ int length;
+
+ text = gtk_editable_get_chars (editable, 0, -1);
+ length = g_utf8_strlen (text, -1);
+ g_free (text);
+ return length;
+}
+
+static void
+set_position_and_selection_to_end (GtkEditable *editable)
+{
+ int end;
+
+ end = get_editable_number_of_chars (editable);
+ gtk_editable_select_region (editable, end, end);
+ gtk_editable_set_position (editable, end);
+}
+
+static gboolean
+position_and_selection_are_at_end (GtkEditable *editable)
+{
+ int end;
+ int start_sel, end_sel;
+
+ end = get_editable_number_of_chars (editable);
+ if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel))
+ {
+ if (start_sel != end || end_sel != end)
+ {
+ return FALSE;
+ }
+ }
+ return gtk_editable_get_position (editable) == end;
+}
+
+static gint
+ephy_keywords_entry_key_press (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GtkEditable *editable;
+ GdkEventKey *keyevent;
+ EphyKeywordsEntry *entry;
+ gboolean result;
+
+ entry = EPHY_KEYWORDS_ENTRY (widget);
+ editable = GTK_EDITABLE (entry);
+ keyevent = (GdkEventKey *)event;
+
+ /* After typing the right arrow key we move the selection to
+ * the end, if we have a valid selection - since this is most
+ * likely an auto-completion. We ignore shift / control since
+ * they can validly be used to extend the selection.
+ */
+ if ((keyevent->keyval == GDK_Right || keyevent->keyval == GDK_End) &&
+ !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) &&
+ gtk_editable_get_selection_bounds (editable, NULL, NULL))
+ {
+ set_position_and_selection_to_end (editable);
+ }
+
+ result = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+
+ /* Only do expanding when we are typing at the end of the
+ * text.
+ */
+ if (entry_would_have_inserted_characters (event)
+ && position_and_selection_are_at_end (editable))
+ {
+ try_to_expand_keyword (editable);
+ }
+
+ g_signal_emit (G_OBJECT (entry), keywords_entry_signals[KEYWORDS_CHANGED], 0);
+
+ return result;
+}
+
+static void
+ephy_keywords_entry_init (EphyKeywordsEntry *w)
+{
+ w->priv = g_new0 (EphyKeywordsEntryPrivate, 1);
+ w->priv->bookmarks = NULL;
+}
+
+static void
+ephy_keywords_entry_finalize_impl (GObject *o)
+{
+ EphyKeywordsEntry *w = EPHY_KEYWORDS_ENTRY (o);
+ EphyKeywordsEntryPrivate *p = w->priv;
+
+ g_free (p);
+ G_OBJECT_CLASS (parent_class)->finalize (o);
+}
+
+GtkWidget *
+ephy_keywords_entry_new (void)
+{
+ return GTK_WIDGET (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL));
+}
+
+void
+ephy_keywords_entry_set_bookmarks (EphyKeywordsEntry *w,
+ EphyBookmarks *bookmarks)
+{
+ w->priv->bookmarks = bookmarks;
+}
diff --git a/src/bookmarks/ephy-keywords-entry.h b/src/bookmarks/ephy-keywords-entry.h
new file mode 100644
index 000000000..5ab5df257
--- /dev/null
+++ b/src/bookmarks/ephy-keywords-entry.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_KEYWORDS_ENTRY_H
+#define EPHY_KEYWORDS_ENTRY_H
+
+#include "ephy-bookmarks.h"
+
+#include <glib-object.h>
+#include <gtk/gtkentry.h>
+
+/* object forward declarations */
+
+typedef struct _EphyKeywordsEntry EphyKeywordsEntry;
+typedef struct _EphyKeywordsEntryClass EphyKeywordsEntryClass;
+typedef struct _EphyKeywordsEntryPrivate EphyKeywordsEntryPrivate;
+
+/**
+ * EphyFolderTbWidget object
+ */
+
+#define EPHY_TYPE_LOCATION_ENTRY (ephy_keywords_entry_get_type())
+#define EPHY_KEYWORDS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyKeywordsEntry))
+#define EPHY_KEYWORDS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyKeywordsEntryClass))
+#define EPHY_IS_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_LOCATION_ENTRY))
+#define EPHY_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_LOCATION_ENTRY))
+#define EPHY_KEYWORDS_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyKeywordsEntryClass))
+
+struct _EphyKeywordsEntryClass
+{
+ GtkEntryClass parent_class;
+
+ void (* keywords_changed) (EphyKeywordsEntry *entry);
+};
+
+struct _EphyKeywordsEntry
+{
+ GtkEntry parent_object;
+
+ EphyKeywordsEntryPrivate *priv;
+};
+
+GType ephy_keywords_entry_get_type (void);
+
+GtkWidget *ephy_keywords_entry_new (void);
+
+void ephy_keywords_entry_set_bookmarks (EphyKeywordsEntry *w,
+ EphyBookmarks *bookmarks);
+
+#endif
diff --git a/src/bookmarks/ephy-new-bookmark.c b/src/bookmarks/ephy-new-bookmark.c
new file mode 100644
index 000000000..ee0d4b983
--- /dev/null
+++ b/src/bookmarks/ephy-new-bookmark.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gtk/gtktable.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkeditable.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "ephy-new-bookmark.h"
+#include "ephy-keywords-entry.h"
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+static void ephy_new_bookmark_class_init (EphyNewBookmarkClass *klass);
+static void ephy_new_bookmark_init (EphyNewBookmark *editor);
+static void ephy_new_bookmark_finalize (GObject *object);
+static void ephy_new_bookmark_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_new_bookmark_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyNewBookmarkPrivate
+{
+ EphyBookmarks *bookmarks;
+ char *location;
+ char *smarturl;
+
+ GtkWidget *title_entry;
+ GtkWidget *keywords_entry;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BOOKMARKS,
+ PROP_LOCATION
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_new_bookmark_get_type (void)
+{
+ static GType ephy_new_bookmark_type = 0;
+
+ if (ephy_new_bookmark_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyNewBookmarkClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_new_bookmark_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyNewBookmark),
+ 0,
+ (GInstanceInitFunc) ephy_new_bookmark_init
+ };
+
+ ephy_new_bookmark_type = g_type_register_static (GTK_TYPE_DIALOG,
+ "EphyNewBookmark",
+ &our_info, 0);
+ }
+
+ return ephy_new_bookmark_type;
+}
+
+static void
+ephy_new_bookmark_class_init (EphyNewBookmarkClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_new_bookmark_finalize;
+
+ object_class->set_property = ephy_new_bookmark_set_property;
+ object_class->get_property = ephy_new_bookmark_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BOOKMARKS,
+ g_param_spec_object ("bookmarks",
+ "Bookmarks set",
+ "Bookmarks set",
+ EPHY_BOOKMARKS_TYPE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_string ("location",
+ "Bookmark location",
+ "Bookmark location",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_new_bookmark_finalize (GObject *object)
+{
+ EphyNewBookmark *editor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_NEW_BOOKMARK (object));
+
+ editor = EPHY_NEW_BOOKMARK (object);
+
+ g_return_if_fail (editor->priv != NULL);
+
+ g_free (editor->priv->location);
+ g_free (editor->priv->smarturl);
+
+ g_free (editor->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_new_bookmark_add (EphyNewBookmark *new_bookmark)
+{
+ char *title;
+ char *keywords;
+
+ title = gtk_editable_get_chars
+ (GTK_EDITABLE (new_bookmark->priv->title_entry), 0, -1);
+ keywords = gtk_editable_get_chars
+ (GTK_EDITABLE (new_bookmark->priv->keywords_entry), 0, -1);
+ ephy_bookmarks_add (new_bookmark->priv->bookmarks, title,
+ new_bookmark->priv->location,
+ new_bookmark->priv->smarturl, keywords);
+}
+
+static void
+ephy_new_bookmark_response_cb (GtkDialog *dialog,
+ int response_id,
+ EphyNewBookmark *new_bookmark)
+{
+ switch (response_id)
+ {
+ case GTK_RESPONSE_CANCEL:
+ break;
+ case GTK_RESPONSE_OK:
+ ephy_new_bookmark_add (new_bookmark);
+ break;
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static GtkWidget *
+build_editing_table (EphyNewBookmark *editor)
+{
+ GtkWidget *table, *label, *entry;
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Title:</b>"));
+ gtk_widget_show (label);
+ entry = gtk_entry_new ();
+ editor->priv->title_entry = entry;
+ gtk_widget_set_size_request (entry, 200, -1);
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Keywords:</b>"));
+ gtk_widget_show (label);
+ entry = ephy_keywords_entry_new ();
+ ephy_keywords_entry_set_bookmarks (EPHY_KEYWORDS_ENTRY (entry),
+ editor->priv->bookmarks);
+ editor->priv->keywords_entry = entry;
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2);
+
+ return table;
+}
+
+static void
+ephy_new_bookmark_construct (EphyNewBookmark *editor)
+{
+ GtkWidget *hbox, *vbox;
+
+ gtk_window_set_title (GTK_WINDOW (editor),
+ _("Add bookmark"));
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (editor), 6);
+ g_signal_connect (G_OBJECT (editor),
+ "response",
+ G_CALLBACK (ephy_new_bookmark_response_cb),
+ editor);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (editor)->vbox), 12);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox),
+ hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ build_editing_table (editor),
+ FALSE, FALSE, 0);
+
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_OK);
+}
+
+GtkWidget *
+ephy_new_bookmark_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent,
+ const char *location)
+{
+ EphyNewBookmark *editor;
+
+ g_assert (bookmarks != NULL);
+
+ editor = EPHY_NEW_BOOKMARK (g_object_new
+ (EPHY_TYPE_NEW_BOOKMARK,
+ "bookmarks", bookmarks,
+ "location", location,
+ NULL));
+
+ if (parent)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
+ }
+
+ ephy_new_bookmark_construct (editor);
+
+ return GTK_WIDGET (editor);
+}
+
+static void
+ephy_new_bookmark_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNewBookmark *editor = EPHY_NEW_BOOKMARK (object);
+
+ switch (prop_id)
+ {
+ case PROP_BOOKMARKS:
+ editor->priv->bookmarks = g_value_get_object (value);
+ break;
+ case PROP_LOCATION:
+ g_free (editor->priv->location);
+ editor->priv->location = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_new_bookmark_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNewBookmark *editor = EPHY_NEW_BOOKMARK (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_string (value, editor->priv->location);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_new_bookmark_init (EphyNewBookmark *editor)
+{
+ editor->priv = g_new0 (EphyNewBookmarkPrivate, 1);
+ editor->priv->location = NULL;
+ editor->priv->smarturl = NULL;
+}
+
+void
+ephy_new_bookmark_set_title (EphyNewBookmark *bookmark,
+ const char *title)
+{
+ DEBUG_MSG (("Setting new bookmark title to: \"%s\"", title));
+ gtk_entry_set_text (GTK_ENTRY (bookmark->priv->title_entry),
+ g_strdup (title));
+}
+
+void
+ephy_new_bookmark_set_smarturl (EphyNewBookmark *bookmark,
+ const char *url)
+{
+ g_free (bookmark->priv->smarturl);
+ bookmark->priv->smarturl = g_strdup (url);
+}
+
diff --git a/src/bookmarks/ephy-new-bookmark.h b/src/bookmarks/ephy-new-bookmark.h
new file mode 100644
index 000000000..7e1091f50
--- /dev/null
+++ b/src/bookmarks/ephy-new-bookmark.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_NEW_BOOKMARK_H
+#define EPHY_NEW_BOOKMARK_H
+
+#include <gtk/gtkdialog.h>
+
+#include "ephy-bookmarks.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NEW_BOOKMARK (ephy_new_bookmark_get_type ())
+#define EPHY_NEW_BOOKMARK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmark))
+#define EPHY_NEW_BOOKMARK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmarkClass))
+#define EPHY_IS_NEW_BOOKMARK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NEW_BOOKMARK))
+#define EPHY_IS_NEW_BOOKMARK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NEW_BOOKMARK))
+#define EPHY_NEW_BOOKMARK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmarkClass))
+
+typedef struct EphyNewBookmarkPrivate EphyNewBookmarkPrivate;
+
+typedef struct
+{
+ GtkDialog parent;
+
+ EphyNewBookmarkPrivate *priv;
+} EphyNewBookmark;
+
+typedef struct
+{
+ GtkDialogClass parent;
+} EphyNewBookmarkClass;
+
+GType ephy_new_bookmark_get_type (void);
+
+GtkWidget *ephy_new_bookmark_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent,
+ const char *location);
+
+void ephy_new_bookmark_set_title (EphyNewBookmark *bookmark,
+ const char *title);
+
+void ephy_new_bookmark_set_smarturl (EphyNewBookmark *bookmark,
+ const char *url);
+
+G_END_DECLS
+
+#endif /* EPHY_NEW_BOOKMARK_H */
diff --git a/src/bookmarks/ephy-node-view.c b/src/bookmarks/ephy-node-view.c
new file mode 100644
index 000000000..f537855d8
--- /dev/null
+++ b/src/bookmarks/ephy-node-view.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtktreeviewcolumn.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "eggtreemodelfilter.h"
+#include "ephy-tree-model-node.h"
+#include "ephy-node-view.h"
+#include "ephy-tree-model-sort.h"
+#include "eggtreemultidnd.h"
+#include "ephy-dnd.h"
+
+static void ephy_node_view_class_init (EphyNodeViewClass *klass);
+static void ephy_node_view_init (EphyNodeView *view);
+static void ephy_node_view_finalize (GObject *object);
+static void ephy_node_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_node_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyNodeViewPrivate
+{
+ EphyNode *root;
+
+ EphyTreeModelNode *nodemodel;
+ GtkTreeModel *filtermodel;
+ GtkTreeModel *sortmodel;
+
+ EphyNodeFilter *filter;
+
+ GtkWidget *treeview;
+};
+
+enum
+{
+ NODE_ACTIVATED,
+ NODE_SELECTED,
+ SHOW_POPUP,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_ROOT,
+ PROP_FILTER
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint ephy_node_view_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_node_view_get_type (void)
+{
+ static GType ephy_node_view_type = 0;
+
+ if (ephy_node_view_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyNodeViewClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_node_view_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyNodeView),
+ 0,
+ (GInstanceInitFunc) ephy_node_view_init
+ };
+
+ ephy_node_view_type = g_type_register_static (GTK_TYPE_SCROLLED_WINDOW,
+ "EphyNodeView",
+ &our_info, 0);
+ }
+
+ return ephy_node_view_type;
+}
+
+static void
+ephy_node_view_class_init (EphyNodeViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_node_view_finalize;
+
+ object_class->set_property = ephy_node_view_set_property;
+ object_class->get_property = ephy_node_view_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root node",
+ "Root node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ g_param_spec_object ("filter",
+ "Filter object",
+ "Filter object",
+ EPHY_TYPE_NODE_FILTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ ephy_node_view_signals[NODE_ACTIVATED] =
+ g_signal_new ("node_activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeViewClass, node_activated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+ ephy_node_view_signals[NODE_SELECTED] =
+ g_signal_new ("node_selected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeViewClass, node_selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+ ephy_node_view_signals[SHOW_POPUP] =
+ g_signal_new ("show_popup",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeViewClass, show_popup),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+ephy_node_view_finalize (GObject *object)
+{
+ EphyNodeView *view;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_NODE_VIEW (object));
+
+ view = EPHY_NODE_VIEW (object);
+
+ g_return_if_fail (view->priv != NULL);
+
+ g_object_unref (G_OBJECT (view->priv->sortmodel));
+ g_object_unref (G_OBJECT (view->priv->filtermodel));
+ g_object_unref (G_OBJECT (view->priv->nodemodel));
+
+ g_free (view->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_changed_cb (EphyNodeFilter *filter,
+ EphyNodeView *view)
+{
+ GtkWidget *window;
+
+ g_return_if_fail (EPHY_IS_NODE_VIEW (view));
+
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+
+ if (window != NULL && window->window != NULL)
+ {
+ /* nice busy cursor */
+ GdkCursor *cursor;
+
+ cursor = gdk_cursor_new (GDK_WATCH);
+ gdk_window_set_cursor (window->window, cursor);
+ gdk_cursor_unref (cursor);
+
+ gdk_flush ();
+
+ gdk_window_set_cursor (window->window, NULL);
+
+ /* no flush: this will cause the cursor to be reset
+ * only when the UI is free again */
+ }
+}
+
+static void
+ephy_node_view_selection_changed_cb (GtkTreeSelection *selection,
+ EphyNodeView *view)
+{
+ GList *list;
+ EphyNode *node = NULL;
+
+ list = ephy_node_view_get_selection (view);
+ if (list)
+ {
+ node = EPHY_NODE (list->data);
+ }
+ g_list_free (list);
+
+ g_signal_emit (G_OBJECT (view), ephy_node_view_signals[NODE_SELECTED], 0, node);
+}
+
+static void
+ephy_node_view_row_activated_cb (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ EphyNodeView *view)
+{
+ GtkTreeIter iter, iter2;
+ EphyNode *node;
+
+ gtk_tree_model_get_iter (view->priv->sortmodel, &iter, path);
+ gtk_tree_model_sort_convert_iter_to_child_iter
+ (GTK_TREE_MODEL_SORT (view->priv->sortmodel), &iter2, &iter);
+ egg_tree_model_filter_convert_iter_to_child_iter
+ (EGG_TREE_MODEL_FILTER (view->priv->filtermodel), &iter, &iter2);
+
+ node = ephy_tree_model_node_node_from_iter (view->priv->nodemodel, &iter);
+
+ g_signal_emit (G_OBJECT (view), ephy_node_view_signals[NODE_ACTIVATED], 0, node);
+}
+
+static gboolean
+ephy_node_view_button_press_cb (GtkTreeView *treeview,
+ GdkEventButton *event,
+ EphyNodeView *view)
+{
+ if (event->button == 3)
+ {
+ g_signal_emit (G_OBJECT (view), ephy_node_view_signals[SHOW_POPUP], 0);
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_node_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNodeView *view = EPHY_NODE_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ view->priv->root = g_value_get_object (value);
+ break;
+ case PROP_FILTER:
+ view->priv->filter = g_value_get_object (value);
+
+ if (view->priv->filter != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (view->priv->filter),
+ "changed",
+ G_CALLBACK (filter_changed_cb),
+ G_OBJECT (view),
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_node_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNodeView *view = EPHY_NODE_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, view->priv->root);
+ break;
+ case PROP_FILTER:
+ g_value_set_object (value, view->priv->filter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+node_from_sort_iter_cb (EphyTreeModelSort *model,
+ GtkTreeIter *iter,
+ void **node,
+ EphyNodeView *view)
+{
+ GtkTreeIter filter_iter, node_iter;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
+ &filter_iter, iter);
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (view->priv->filtermodel),
+ &node_iter, &filter_iter);
+ *node = ephy_tree_model_node_node_from_iter
+ (EPHY_TREE_MODEL_NODE (view->priv->nodemodel), &node_iter);
+}
+
+static void
+ephy_node_view_construct (EphyNodeView *view)
+{
+ GtkTreeSelection *selection;
+
+
+ view->priv->nodemodel = ephy_tree_model_node_new (view->priv->root,
+ view->priv->filter);
+ view->priv->filtermodel = egg_tree_model_filter_new (GTK_TREE_MODEL (view->priv->nodemodel),
+ NULL);
+ egg_tree_model_filter_set_visible_column (EGG_TREE_MODEL_FILTER (view->priv->filtermodel),
+ EPHY_TREE_MODEL_NODE_COL_VISIBLE);
+ view->priv->sortmodel = ephy_tree_model_sort_new (view->priv->filtermodel);
+ g_signal_connect_object (G_OBJECT (view->priv->sortmodel),
+ "node_from_iter",
+ G_CALLBACK (node_from_sort_iter_cb),
+ view,
+ 0);
+ view->priv->treeview = gtk_tree_view_new_with_model
+ (GTK_TREE_MODEL (view->priv->sortmodel));
+ gtk_widget_show (view->priv->treeview);
+ g_signal_connect_object (G_OBJECT (view->priv->treeview),
+ "button_press_event",
+ G_CALLBACK (ephy_node_view_button_press_cb),
+ view,
+ 0);
+ g_signal_connect_object (G_OBJECT (view->priv->treeview),
+ "row_activated",
+ G_CALLBACK (ephy_node_view_row_activated_cb),
+ view,
+ 0);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ g_signal_connect_object (G_OBJECT (selection),
+ "changed",
+ G_CALLBACK (ephy_node_view_selection_changed_cb),
+ view,
+ 0);
+
+ gtk_container_add (GTK_CONTAINER (view), view->priv->treeview);
+}
+
+EphyNodeView *
+ephy_node_view_new (EphyNode *root,
+ EphyNodeFilter *filter)
+{
+ EphyNodeView *view;
+
+ view = EPHY_NODE_VIEW (g_object_new (EPHY_TYPE_NODE_VIEW,
+ "filter", filter,
+ "hadjustment", NULL,
+ "vadjustment", NULL,
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "root", root,
+ NULL));
+
+ ephy_node_view_construct (view);
+
+ g_return_val_if_fail (view->priv != NULL, NULL);
+
+ return view;
+}
+
+void
+ephy_node_view_add_column (EphyNodeView *view,
+ const char *title,
+ EphyTreeModelNodeColumn column,
+ gboolean sortable)
+{
+ GtkTreeViewColumn *gcolumn;
+ GtkCellRenderer *renderer;
+
+ gcolumn = (GtkTreeViewColumn *) gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (gcolumn, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (gcolumn, renderer,
+ "text", column,
+ NULL);
+ gtk_tree_view_column_set_sizing (gcolumn,
+ GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_title (gcolumn, title);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview),
+ gcolumn);
+ if (sortable)
+ {
+ gtk_tree_view_column_set_sort_column_id (gcolumn, column);
+ }
+}
+
+static void
+ephy_node_view_init (EphyNodeView *view)
+{
+ view->priv = g_new0 (EphyNodeViewPrivate, 1);
+}
+
+static void
+get_selection (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ void **data)
+{
+ GtkTreeModelSort *sortmodel = GTK_TREE_MODEL_SORT (model);
+ EggTreeModelFilter *filtermodel = EGG_TREE_MODEL_FILTER (sortmodel->child_model);
+ EphyTreeModelNode *nodemodel = EPHY_TREE_MODEL_NODE (filtermodel->child_model);
+ GList **list = (GList **) data;
+ GtkTreeIter *iter2 = gtk_tree_iter_copy (iter);
+ GtkTreeIter iter3;
+ GtkTreeIter iter4;
+ EphyNode *node;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
+ &iter3, iter2);
+ egg_tree_model_filter_convert_iter_to_child_iter (filtermodel, &iter4, &iter3);
+
+ node = ephy_tree_model_node_node_from_iter (nodemodel, &iter4);
+
+ gtk_tree_iter_free (iter2);
+
+ *list = g_list_prepend (*list, node);
+}
+
+GList *
+ephy_node_view_get_selection (EphyNodeView *view)
+{
+ GList *list = NULL;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (view->priv->treeview));
+
+ gtk_tree_selection_selected_foreach (selection,
+ (GtkTreeSelectionForeachFunc) get_selection,
+ (void **) &list);
+
+ return list;
+}
+
+void
+ephy_node_view_remove (EphyNodeView *view)
+{
+ GList *list;
+
+ list = ephy_node_view_get_selection (view);
+
+ for (; list != NULL; list = list->next)
+ {
+ ephy_node_unref (EPHY_NODE (list->data));
+ }
+
+ g_list_free (list);
+}
+
+void
+ephy_node_view_set_browse_mode (EphyNodeView *view)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+}
+
+void
+ephy_node_view_select_node (EphyNodeView *view,
+ EphyNode *node)
+{
+ GtkTreeIter iter, iter2;
+ GValue val = { 0, };
+ gboolean visible;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
+
+ g_return_if_fail (node != NULL);
+
+ ephy_tree_model_node_iter_from_node (EPHY_TREE_MODEL_NODE (view->priv->nodemodel),
+ node, &iter);
+ gtk_tree_model_get_value (GTK_TREE_MODEL (view->priv->nodemodel), &iter,
+ EPHY_TREE_MODEL_NODE_COL_VISIBLE, &val);
+ visible = g_value_get_boolean (&val);
+ g_value_unset (&val);
+ if (visible == FALSE) return;
+
+ egg_tree_model_filter_convert_child_iter_to_iter (EGG_TREE_MODEL_FILTER (view->priv->filtermodel),
+ &iter2, &iter);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (view->priv->sortmodel),
+ &iter, &iter2);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+}
+
+void
+ephy_node_view_enable_drag_source (EphyNodeView *view)
+{
+ g_return_if_fail (view != NULL);
+
+ egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (view->priv->treeview));
+ ephy_dnd_enable_model_drag_source (GTK_WIDGET (view->priv->treeview));
+}
diff --git a/src/bookmarks/ephy-node-view.h b/src/bookmarks/ephy-node-view.h
new file mode 100644
index 000000000..71f19d7c7
--- /dev/null
+++ b/src/bookmarks/ephy-node-view.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __EPHY_NODE_VIEW_H
+#define __EPHY_NODE_VIEW_H
+
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkdnd.h>
+
+#include "ephy-tree-model-node.h"
+#include "ephy-node-filter.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NODE_VIEW (ephy_node_view_get_type ())
+#define EPHY_NODE_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE_VIEW, EphyNodeView))
+#define EPHY_NODE_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE_VIEW, EphyNodeViewClass))
+#define EPHY_IS_NODE_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE_VIEW))
+#define EPHY_IS_NODE_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE_VIEW))
+#define EPHY_NODE_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE_VIEW, EphyNodeViewClass))
+
+typedef struct EphyNodeViewPrivate EphyNodeViewPrivate;
+
+typedef struct
+{
+ GtkScrolledWindow parent;
+
+ EphyNodeViewPrivate *priv;
+} EphyNodeView;
+
+typedef struct
+{
+ GtkScrolledWindowClass parent;
+
+ void (*node_activated) (EphyNodeView *view, EphyNode *node);
+ void (*node_selected) (EphyNodeView *view, EphyNode *node);
+ void (*show_popup) (EphyNodeView *view);
+} EphyNodeViewClass;
+
+GType ephy_node_view_get_type (void);
+
+EphyNodeView *ephy_node_view_new (EphyNode *root,
+ EphyNodeFilter *filter);
+
+void ephy_node_view_enable_dnd (EphyNodeView *view);
+
+void ephy_node_view_add_column (EphyNodeView *view,
+ const char *title,
+ EphyTreeModelNodeColumn column,
+ gboolean sortable);
+
+void ephy_node_view_remove (EphyNodeView *view);
+
+GList *ephy_node_view_get_selection (EphyNodeView *view);
+
+void ephy_node_view_set_browse_mode (EphyNodeView *view);
+
+void ephy_node_view_select_node (EphyNodeView *view,
+ EphyNode *node);
+
+void ephy_node_view_enable_drag_source (EphyNodeView *view);
+
+G_END_DECLS
+
+#endif /* EPHY_NODE_VIEW_H */
diff --git a/src/bookmarks/ephy-tree-model-node.c b/src/bookmarks/ephy-tree-model-node.c
new file mode 100644
index 000000000..d1030d5da
--- /dev/null
+++ b/src/bookmarks/ephy-tree-model-node.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <config.h>
+#include <gtk/gtktreeview.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libgnome/gnome-i18n.h>
+#include <time.h>
+#include <string.h>
+
+#include "ephy-node-filter.h"
+#include "ephy-bookmarks.h"
+#include "ephy-tree-model-node.h"
+#include "ephy-stock-icons.h"
+#include "ephy-node.h"
+
+static void ephy_tree_model_node_class_init (EphyTreeModelNodeClass *klass);
+static void ephy_tree_model_node_init (EphyTreeModelNode *model);
+static void ephy_tree_model_node_finalize (GObject *object);
+static void ephy_tree_model_node_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_tree_model_node_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static guint ephy_tree_model_node_get_flags (GtkTreeModel *tree_model);
+static int ephy_tree_model_node_get_n_columns (GtkTreeModel *tree_model);
+static GType ephy_tree_model_node_get_column_type (GtkTreeModel *tree_model,
+ int index);
+static gboolean ephy_tree_model_node_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath *ephy_tree_model_node_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static void ephy_tree_model_node_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value);
+static gboolean ephy_tree_model_node_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_tree_model_node_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean ephy_tree_model_node_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static int ephy_tree_model_node_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_tree_model_node_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n);
+static gboolean ephy_tree_model_node_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+static void ephy_tree_model_node_tree_model_init (GtkTreeModelIface *iface);
+static void root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model);
+static void root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model);
+static void root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model);
+static inline void ephy_tree_model_node_update_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ int idx);
+static void root_destroyed_cb (EphyNode *node,
+ EphyTreeModelNode *model);
+static inline GtkTreePath *get_path_real (EphyTreeModelNode *model,
+ EphyNode *node);
+
+struct EphyTreeModelNodePrivate
+{
+ EphyNode *root;
+
+ EphyNodeFilter *filter;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ROOT,
+ PROP_FILTER
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_tree_model_node_get_type (void)
+{
+ static GType ephy_tree_model_node_type = 0;
+
+ if (ephy_tree_model_node_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyTreeModelNodeClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_tree_model_node_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyTreeModelNode),
+ 0,
+ (GInstanceInitFunc) ephy_tree_model_node_init
+ };
+
+ static const GInterfaceInfo tree_model_info =
+ {
+ (GInterfaceInitFunc) ephy_tree_model_node_tree_model_init,
+ NULL,
+ NULL
+ };
+
+ ephy_tree_model_node_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyTreeModelNode",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_tree_model_node_type,
+ GTK_TYPE_TREE_MODEL,
+ &tree_model_info);
+ }
+
+ return ephy_tree_model_node_type;
+}
+
+static void
+ephy_tree_model_node_class_init (EphyTreeModelNodeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_tree_model_node_finalize;
+
+ object_class->set_property = ephy_tree_model_node_set_property;
+ object_class->get_property = ephy_tree_model_node_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root node",
+ "Root node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ g_param_spec_object ("filter",
+ "Filter object",
+ "Filter object",
+ EPHY_TYPE_NODE_FILTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_tree_model_node_init (EphyTreeModelNode *model)
+{
+ GtkWidget *dummy;
+
+ do
+ {
+ model->stamp = g_random_int ();
+ }
+ while (model->stamp == 0);
+
+ model->priv = g_new0 (EphyTreeModelNodePrivate, 1);
+
+ dummy = gtk_tree_view_new ();
+
+ gtk_widget_destroy (dummy);
+}
+
+static void
+ephy_tree_model_node_finalize (GObject *object)
+{
+ EphyTreeModelNode *model;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_TREE_MODEL_NODE (object));
+
+ model = EPHY_TREE_MODEL_NODE (object);
+
+ g_return_if_fail (model->priv != NULL);
+
+ g_free (model->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_changed_cb (EphyNodeFilter *filter,
+ EphyTreeModelNode *model)
+{
+ GPtrArray *kids;
+ int i;
+
+ kids = ephy_node_get_children (model->priv->root);
+
+ for (i = 0; i < kids->len; i++)
+ {
+ ephy_tree_model_node_update_node (model,
+ g_ptr_array_index (kids, i),
+ i);
+ }
+
+ ephy_node_thaw (model->priv->root);
+}
+
+static void
+ephy_tree_model_node_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ model->priv->root = g_value_get_object (value);
+
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_added",
+ G_CALLBACK (root_child_added_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_removed",
+ G_CALLBACK (root_child_removed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_changed",
+ G_CALLBACK (root_child_changed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "destroyed",
+ G_CALLBACK (root_destroyed_cb),
+ G_OBJECT (model),
+ 0);
+
+ break;
+ case PROP_FILTER:
+ model->priv->filter = g_value_get_object (value);
+
+ if (model->priv->filter != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (model->priv->filter),
+ "changed",
+ G_CALLBACK (filter_changed_cb),
+ G_OBJECT (model),
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_tree_model_node_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, model->priv->root);
+ break;
+ case PROP_FILTER:
+ g_value_set_object (value, model->priv->filter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+EphyTreeModelNode *
+ephy_tree_model_node_new (EphyNode *root,
+ EphyNodeFilter *filter)
+{
+ EphyTreeModelNode *model;
+
+ model = EPHY_TREE_MODEL_NODE (g_object_new (EPHY_TYPE_TREE_MODEL_NODE,
+ "filter", filter,
+ "root", root,
+ NULL));
+
+ g_return_val_if_fail (model->priv != NULL, NULL);
+
+ return model;
+}
+
+static void
+ephy_tree_model_node_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = ephy_tree_model_node_get_flags;
+ iface->get_n_columns = ephy_tree_model_node_get_n_columns;
+ iface->get_column_type = ephy_tree_model_node_get_column_type;
+ iface->get_iter = ephy_tree_model_node_get_iter;
+ iface->get_path = ephy_tree_model_node_get_path;
+ iface->get_value = ephy_tree_model_node_get_value;
+ iface->iter_next = ephy_tree_model_node_iter_next;
+ iface->iter_children = ephy_tree_model_node_iter_children;
+ iface->iter_has_child = ephy_tree_model_node_iter_has_child;
+ iface->iter_n_children = ephy_tree_model_node_iter_n_children;
+ iface->iter_nth_child = ephy_tree_model_node_iter_nth_child;
+ iface->iter_parent = ephy_tree_model_node_iter_parent;
+}
+
+static guint
+ephy_tree_model_node_get_flags (GtkTreeModel *tree_model)
+{
+ return 0;
+}
+
+static int
+ephy_tree_model_node_get_n_columns (GtkTreeModel *tree_model)
+{
+ return EPHY_TREE_MODEL_NODE_NUM_COLUMNS;
+}
+
+static GType
+ephy_tree_model_node_get_column_type (GtkTreeModel *tree_model,
+ int index)
+{
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail ((index < EPHY_TREE_MODEL_NODE_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
+
+ switch (index)
+ {
+ case EPHY_TREE_MODEL_NODE_COL_BOOKMARK:
+ case EPHY_TREE_MODEL_NODE_COL_LOCATION:
+ case EPHY_TREE_MODEL_NODE_COL_KEYWORD:
+ return G_TYPE_STRING;
+ case EPHY_TREE_MODEL_NODE_COL_VISIBLE:
+ return G_TYPE_BOOLEAN;
+ default:
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+ephy_tree_model_node_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ int i;
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (model), FALSE);
+ g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ i = gtk_tree_path_get_indices (path)[0];
+
+ iter->stamp = model->stamp;
+ iter->user_data = ephy_node_get_nth_child (model->priv->root, i);
+
+ if (iter->user_data == NULL)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline GtkTreePath *
+get_path_real (EphyTreeModelNode *model,
+ EphyNode *node)
+{
+ GtkTreePath *retval;
+
+ retval = gtk_tree_path_new ();
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (model->priv->root, node));
+
+ return retval;
+}
+
+static GtkTreePath *
+ephy_tree_model_node_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
+ g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+ if (model->priv->root == NULL)
+ return NULL;
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (node == model->priv->root)
+ return gtk_tree_path_new ();
+
+ return get_path_real (model, node);
+}
+
+static void
+ephy_tree_model_node_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->stamp == model->stamp);
+ g_return_if_fail (EPHY_IS_NODE (iter->user_data));
+ g_return_if_fail (column < EPHY_TREE_MODEL_NODE_NUM_COLUMNS);
+
+ if (model->priv->root == NULL)
+ return;
+
+ node = EPHY_NODE (iter->user_data);
+
+ switch (column)
+ {
+ case EPHY_TREE_MODEL_NODE_COL_BOOKMARK:
+ ephy_node_get_property (node,
+ EPHY_NODE_BMK_PROP_TITLE,
+ value);
+ break;
+ case EPHY_TREE_MODEL_NODE_COL_LOCATION:
+ ephy_node_get_property (node,
+ EPHY_NODE_BMK_PROP_LOCATION,
+ value);
+ break;
+ case EPHY_TREE_MODEL_NODE_COL_KEYWORD:
+ ephy_node_get_property (node,
+ EPHY_NODE_KEYWORD_PROP_NAME,
+ value);
+ break;
+ case EPHY_TREE_MODEL_NODE_COL_VISIBLE:
+ g_value_init (value, G_TYPE_BOOLEAN);
+
+ if (model->priv->filter != NULL)
+ {
+ g_value_set_boolean (value,
+ ephy_node_filter_evaluate (model->priv->filter, node));
+ }
+ else
+ {
+ g_value_set_boolean (value, TRUE);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+ephy_tree_model_node_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+ g_return_val_if_fail (iter->stamp == EPHY_TREE_MODEL_NODE (tree_model)->stamp, FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (node == model->priv->root)
+ return FALSE;
+
+ iter->user_data = ephy_node_get_next_child (model->priv->root, node);
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_tree_model_node_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ if (parent != NULL)
+ return FALSE;
+
+ iter->stamp = model->stamp;
+ iter->user_data = model->priv->root;
+
+ return TRUE;
+}
+
+static gboolean
+ephy_tree_model_node_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return FALSE;
+}
+
+static int
+ephy_tree_model_node_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), -1);
+
+ if (model->priv->root == NULL)
+ return 0;
+
+ if (iter == NULL)
+ return ephy_node_get_n_children (model->priv->root);
+
+ g_return_val_if_fail (model->stamp == iter->stamp, -1);
+
+ return 0;
+}
+
+static gboolean
+ephy_tree_model_node_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ if (parent != NULL)
+ return FALSE;
+
+ node = ephy_node_get_nth_child (model->priv->root, n);
+
+ if (node != NULL)
+ {
+ iter->stamp = model->stamp;
+ iter->user_data = node;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+ephy_tree_model_node_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+EphyNode *
+ephy_tree_model_node_node_from_iter (EphyTreeModelNode *model,
+ GtkTreeIter *iter)
+{
+ return EPHY_NODE (iter->user_data);
+}
+
+void
+ephy_tree_model_node_iter_from_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ GtkTreeIter *iter)
+{
+ iter->stamp = model->stamp;
+ iter->user_data = node;
+}
+
+static void
+root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model)
+{
+ GtkTreePath *path;
+
+ path = get_path_real (model, child);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_tree_model_node_iter_from_node (model, child, &iter);
+
+ path = get_path_real (model, child);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static inline void
+ephy_tree_model_node_update_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ int idx)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_tree_model_node_iter_from_node (model, node, &iter);
+
+ if (idx >= 0)
+ {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, idx);
+ }
+ else
+ {
+ path = get_path_real (model, node);
+ }
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model)
+{
+ ephy_tree_model_node_update_node (model, child, -1);
+}
+
+static void
+root_destroyed_cb (EphyNode *node,
+ EphyTreeModelNode *model)
+{
+ model->priv->root = NULL;
+
+ /* no need to do other stuff since we should have had a bunch of child_removed
+ * signals already */
+}
+
+GType
+ephy_tree_model_node_column_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0)
+ {
+ static const GEnumValue values[] =
+ {
+ { EPHY_TREE_MODEL_NODE_COL_BOOKMARK, "EPHY_TREE_MODEL_NODE_COL_BOOKMARK", "bookmark" },
+ { EPHY_TREE_MODEL_NODE_COL_LOCATION, "EPHY_TREE_MODEL_NODE_COL_LOCATION", "location" },
+ { EPHY_TREE_MODEL_NODE_COL_KEYWORD, "EPHY_TREE_MODEL_NODE_COL_KEYWORD", "keyword" },
+ { EPHY_TREE_MODEL_NODE_COL_VISIBLE, "EPHY_TREE_MODEL_NODE_COL_VISIBLE", "visible" },
+
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("EphyTreeModelNodeColumn", values);
+ }
+
+ return etype;
+}
+
diff --git a/src/bookmarks/ephy-tree-model-node.h b/src/bookmarks/ephy-tree-model-node.h
new file mode 100644
index 000000000..a48bc6ad5
--- /dev/null
+++ b/src/bookmarks/ephy-tree-model-node.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __EPHY_TREE_MODEL_NODE_H
+#define __EPHY_TREE_MODEL_NODE_H
+
+#include <gtk/gtktreemodel.h>
+
+#include "ephy-node.h"
+#include "ephy-node-filter.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_TREE_MODEL_NODE (ephy_tree_model_node_get_type ())
+#define EPHY_TREE_MODEL_NODE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNode))
+#define EPHY_TREE_MODEL_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNodeClass))
+#define EPHY_IS_TREE_MODEL_NODE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_TREE_MODEL_NODE))
+#define EPHY_IS_TREE_MODEL_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_TREE_MODEL_NODE))
+#define EPHY_TREE_MODEL_NODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNodeClass))
+
+typedef enum
+{
+ EPHY_TREE_MODEL_NODE_COL_BOOKMARK,
+ EPHY_TREE_MODEL_NODE_COL_LOCATION,
+ EPHY_TREE_MODEL_NODE_COL_KEYWORD,
+ EPHY_TREE_MODEL_NODE_COL_VISIBLE,
+ EPHY_TREE_MODEL_NODE_NUM_COLUMNS
+} EphyTreeModelNodeColumn;
+
+GType ephy_tree_model_node_column_get_type (void);
+
+#define EPHY_TYPE_TREE_MODEL_NODE_COLUMN (ephy_tree_model_node_column_get_type ())
+
+typedef struct EphyTreeModelNodePrivate EphyTreeModelNodePrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyTreeModelNodePrivate *priv;
+
+ int stamp;
+} EphyTreeModelNode;
+
+typedef struct
+{
+ GObjectClass parent;
+} EphyTreeModelNodeClass;
+
+GType ephy_tree_model_node_get_type (void);
+
+EphyTreeModelNode *ephy_tree_model_node_new (EphyNode *root,
+ EphyNodeFilter *filter);
+
+EphyNode *ephy_tree_model_node_node_from_iter (EphyTreeModelNode *model,
+ GtkTreeIter *iter);
+
+void ephy_tree_model_node_iter_from_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ GtkTreeIter *iter);
+
+G_END_DECLS
+
+#endif /* EPHY_TREE_MODEL_NODE_H */
diff --git a/src/ephy-automation.c b/src/ephy-automation.c
new file mode 100644
index 000000000..d7757fe75
--- /dev/null
+++ b/src/ephy-automation.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-automation.h"
+#include "ephy-shell.h"
+#include "EphyAutomation.h"
+#include "ephy-embed.h"
+#include "ephy-window.h"
+
+#include <string.h>
+#include <bonobo/bonobo-generic-factory.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-context.h>
+
+static CORBA_boolean
+impl_ephy_automation_add_bookmark (PortableServer_Servant _servant,
+ const CORBA_char * url,
+ CORBA_Environment * ev);
+static CORBA_boolean
+impl_ephy_automation_quit (PortableServer_Servant _servant,
+ const CORBA_boolean disableServer,
+ CORBA_Environment * ev);
+static CORBA_boolean
+impl_ephy_automation_load_session (PortableServer_Servant _servant,
+ const CORBA_char * filename,
+ CORBA_Environment * ev);
+static void
+ephy_automation_class_init (EphyAutomationClass *klass);
+static void
+ephy_automation_init (EphyAutomation *a);
+static void
+ephy_automation_object_finalize (GObject *object);
+static BonoboObject *
+ephy_automation_factory (BonoboGenericFactory *this_factory,
+ const char *iid,
+ gpointer user_data);
+
+static GObjectClass *ephy_automation_parent_class;
+
+#define EPHY_FACTORY_OAFIID "OAFIID:GNOME_Epiphany_Automation_Factory"
+
+static BonoboObject *
+ephy_automation_factory (BonoboGenericFactory *this_factory,
+ const char *iid,
+ gpointer user_data)
+{
+ EphyAutomation *a;
+
+ a = g_object_new (EPHY_AUTOMATION_TYPE, NULL);
+
+ return BONOBO_OBJECT(a);
+}
+
+BonoboObject *
+ephy_automation_new (void)
+{
+ BonoboGenericFactory *factory;
+
+ factory = bonobo_generic_factory_new (EPHY_FACTORY_OAFIID,
+ ephy_automation_factory,
+ NULL);
+
+ g_return_val_if_fail (factory != NULL, NULL);
+
+ return BONOBO_OBJECT (factory);
+}
+
+static CORBA_boolean
+impl_ephy_automation_loadurl (PortableServer_Servant _servant,
+ const CORBA_char * url,
+ const CORBA_char * geometry,
+ const CORBA_boolean fullscreen,
+ const CORBA_boolean open_in_existing_tab,
+ const CORBA_boolean open_in_new_window,
+ const CORBA_boolean open_in_new_tab,
+ const CORBA_boolean raise,
+ CORBA_Environment * ev)
+{
+ EphyNewTabFlags flags = 0;
+ const char *load_page = NULL;
+ EphyWindow *window;
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+
+ /* no window open, let's try to autoresume */
+ if (session_get_windows (session) == NULL)
+ {
+ gboolean res;
+ res = session_autoresume (session);
+ /* no need to open the homepage,
+ * we did already open session windows */
+ if (res && *url == '\0') return TRUE;
+ }
+
+ window = ephy_shell_get_active_window (ephy_shell);
+
+ if (open_in_existing_tab && window != NULL)
+ {
+ ephy_window_load_url (window, url);
+ return TRUE;
+ }
+
+ if (*url == '\0')
+ {
+ flags = EPHY_NEW_TAB_HOMEPAGE;
+ }
+ else
+ {
+ load_page = url;
+ }
+
+ if (open_in_new_window)
+ {
+ flags |= EPHY_NEW_TAB_IN_NEW_WINDOW;
+ }
+
+ if (open_in_new_tab)
+ {
+ flags |= EPHY_NEW_TAB_IN_EXISTING_WINDOW;
+ }
+
+ ephy_shell_new_tab (ephy_shell, window, NULL, load_page,
+ flags);
+
+ return TRUE;
+}
+
+static CORBA_boolean
+impl_ephy_automation_add_bookmark (PortableServer_Servant _servant,
+ const CORBA_char * url,
+ CORBA_Environment * ev)
+{
+ CORBA_boolean retval = TRUE;
+ return retval;
+}
+
+static CORBA_boolean
+impl_ephy_automation_quit (PortableServer_Servant _servant,
+ const CORBA_boolean disableServer,
+ CORBA_Environment * ev)
+{
+ CORBA_boolean retval = TRUE;
+
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+
+ session_close (session);
+
+ return retval;
+}
+
+static CORBA_boolean
+impl_ephy_automation_load_session (PortableServer_Servant _servant,
+ const CORBA_char * filename,
+ CORBA_Environment * ev)
+{
+ CORBA_boolean retval = TRUE;
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+ session_load (session, filename);
+
+ return retval;
+}
+
+static void
+ephy_automation_class_init (EphyAutomationClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ POA_GNOME_EphyAutomation__epv *epv = &klass->epv;
+
+ ephy_automation_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_automation_object_finalize;
+
+ /* connect implementation callbacks */
+ epv->loadurl = impl_ephy_automation_loadurl;
+ epv->addBookmark = impl_ephy_automation_add_bookmark;
+ epv->quit = impl_ephy_automation_quit;
+ epv->loadSession = impl_ephy_automation_load_session;
+}
+
+static void
+ephy_automation_init (EphyAutomation *c)
+{
+}
+
+static void
+ephy_automation_object_finalize (GObject *object)
+{
+ EphyAutomation *a = EPHY_AUTOMATION (object);
+
+ ephy_automation_parent_class->finalize (G_OBJECT (a));
+}
+
+BONOBO_TYPE_FUNC_FULL (
+ EphyAutomation,
+ GNOME_EphyAutomation,
+ BONOBO_TYPE_OBJECT,
+ ephy_automation);
diff --git a/src/ephy-automation.h b/src/ephy-automation.h
new file mode 100644
index 000000000..4b3701605
--- /dev/null
+++ b/src/ephy-automation.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _EPHY_AUTOMATION_H_
+#define _EPHY_AUTOMATION_H_
+
+#include "EphyAutomation.h"
+
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-object.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_AUTOMATION_TYPE (ephy_automation_get_type ())
+#define EPHY_AUTOMATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_AUTOMATION_TYPE, EphyAutomation))
+#define EPHY_AUTOMATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_AUTOMATION_TYPE, EphyAutomationClass))
+#define EPHY_AUTOMATION_IS_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_AUTOMATION_TYPE))
+#define EPHY_AUTOMATION_IS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_AUTOMATION_TYPE))
+#define EPHY_AUTOMATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_AUTOMATION_TYPE, EphyAutomationClass))
+
+typedef struct {
+ BonoboObject parent;
+} EphyAutomation;
+
+typedef struct {
+ BonoboObjectClass parent_class;
+
+ POA_GNOME_EphyAutomation__epv epv;
+} EphyAutomationClass;
+
+GType ephy_automation_get_type (void);
+
+BonoboObject *ephy_automation_new (void);
+
+G_END_DECLS
+
+#endif /* _EPHY_AUTOMATION_H_ */
diff --git a/src/ephy-favorites-menu.c b/src/ephy-favorites-menu.c
new file mode 100644
index 000000000..d8f44f852
--- /dev/null
+++ b/src/ephy-favorites-menu.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ephy-favorites-menu.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-string.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-marshal.h"
+#include "ephy-shell.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <libxml/entities.h>
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define MAX_LABEL_LENGTH 30
+
+/**
+ * Private data
+ */
+struct _EphyFavoritesMenuPrivate
+{
+ gchar *path;
+ EphyWindow *window;
+ EphyBookmarks *bookmarks;
+};
+
+typedef struct
+{
+ EphyWindow *window;
+ const char *url;
+} FavoriteData;
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_favorites_menu_class_init (EphyFavoritesMenuClass *klass);
+static void ephy_favorites_menu_init (EphyFavoritesMenu *wrhm);
+static void ephy_favorites_menu_finalize_impl (GObject *o);
+static void ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm);
+static void ephy_favorites_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_favorites_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+static gpointer g_object_class;
+
+/**
+ * EphyFavoritesMenu object
+ */
+MAKE_GET_TYPE (ephy_favorites_menu,
+ "EphyFavoritesMenu", EphyFavoritesMenu,
+ ephy_favorites_menu_class_init, ephy_favorites_menu_init,
+ G_TYPE_OBJECT);
+
+static void
+ephy_favorites_menu_class_init (EphyFavoritesMenuClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = ephy_favorites_menu_finalize_impl;
+ g_object_class = g_type_class_peek_parent (klass);
+
+ object_class->set_property = ephy_favorites_menu_set_property;
+ object_class->get_property = ephy_favorites_menu_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+ephy_favorites_menu_init (EphyFavoritesMenu *wrhm)
+{
+ EphyFavoritesMenuPrivate *p = g_new0 (EphyFavoritesMenuPrivate, 1);
+ wrhm->priv = p;
+
+ wrhm->priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+}
+
+static void
+ephy_favorites_menu_finalize_impl (GObject *o)
+{
+ EphyFavoritesMenu *wrhm = EPHY_FAVORITES_MENU (o);
+ EphyFavoritesMenuPrivate *p = wrhm->priv;
+
+ if (p->path)
+ {
+ g_free (p->path);
+ }
+
+ g_free (p);
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+static void
+ephy_favorites_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFavoritesMenu *m = EPHY_FAVORITES_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ m->priv->window = g_value_get_object (value);
+ break;
+ }
+}
+
+static void
+ephy_favorites_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFavoritesMenu *m = EPHY_FAVORITES_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, m->priv->window);
+ break;
+ }
+}
+
+EphyFavoritesMenu *
+ephy_favorites_menu_new (EphyWindow *window)
+{
+ EphyFavoritesMenu *ret = g_object_new (EPHY_TYPE_FAVORITES_MENU,
+ "EphyWindow", window,
+ NULL);
+ return ret;
+}
+
+void
+ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm,
+ const gchar *path)
+{
+ EphyFavoritesMenuPrivate *p;
+
+ g_return_if_fail (EPHY_IS_FAVORITES_MENU (wrhm));
+ g_return_if_fail (path != NULL);
+
+ p = wrhm->priv;
+
+ if (p->path)
+ {
+ g_free (p->path);
+ }
+ p->path = g_strdup (path);
+
+ ephy_favorites_menu_update (wrhm);
+}
+
+static void
+ephy_favorites_menu_verb_cb (BonoboUIComponent *uic,
+ FavoriteData *data,
+ const char *cname)
+{
+ ephy_window_load_url (data->window, data->url);
+}
+
+static void
+ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm)
+{
+ EphyFavoritesMenuPrivate *p = wrhm->priv;
+ GString *xml;
+ gint i;
+ EphyNode *fav;
+ GPtrArray *children;
+ BonoboUIComponent *uic = BONOBO_UI_COMPONENT (p->window->ui_component);
+
+ if (!p->path) return;
+
+ ephy_bonobo_clear_path (uic, p->path);
+
+ DEBUG_MSG (("Rebuilding recent history menu\n"));
+
+ fav = ephy_bookmarks_get_favorites (p->bookmarks);
+ children = ephy_node_get_children (fav);
+
+ xml = g_string_new (NULL);
+ g_string_append_printf (xml, "<placeholder name=\"wrhm%x\">\n", (guint) wrhm);
+
+ for (i = 0; i < children->len; i++)
+ {
+ char *verb = g_strdup_printf ("Wrhm%xn%d", (guint) wrhm, i);
+ char *title_s;
+ const char *title;
+ const char *url;
+ xmlChar *label_x;
+ EphyNode *child;
+ FavoriteData *data;
+
+ child = g_ptr_array_index (children, i);
+ title = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_TITLE);
+ url = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION);
+ title_s = ephy_string_shorten (title, MAX_LABEL_LENGTH);
+ label_x = xmlEncodeSpecialChars (NULL, title_s);
+
+ g_string_append (xml, "<menuitem name=\"");
+ g_string_append (xml, verb);
+ g_string_append (xml, "\" label=\"");
+ g_string_append (xml, label_x);
+ g_string_append (xml, "\" verb=\"");
+ g_string_append (xml, verb);
+ g_string_append (xml, "\"/>\n");
+
+ data = g_new0 (FavoriteData, 1);
+ data->window = wrhm->priv->window;
+ data->url = url;
+ bonobo_ui_component_add_verb_full (uic, verb, g_cclosure_new
+ (G_CALLBACK (ephy_favorites_menu_verb_cb), data,
+ (GClosureNotify)g_free));
+
+ xmlFree (label_x);
+ g_free (title_s);
+ g_free (verb);
+ }
+
+ ephy_node_thaw (fav);
+
+ g_string_append (xml, "</placeholder>\n");
+ DEBUG_MSG (("\n%s\n", xml->str));
+ if (children->len > 0)
+ {
+ bonobo_ui_component_set (uic, p->path,
+ xml->str, NULL);
+ }
+ g_string_free (xml, TRUE);
+}
+
+void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm)
+{
+ ephy_favorites_menu_rebuild (wrhm);
+}
diff --git a/src/ephy-favorites-menu.h b/src/ephy-favorites-menu.h
new file mode 100644
index 000000000..b76e8d2d8
--- /dev/null
+++ b/src/ephy-favorites-menu.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_FAVORITES_MENU_H
+#define EPHY_FAVORITES_MENU_H
+
+#include "ephy-window.h"
+
+#include <bonobo/bonobo-ui-component.h>
+
+/* object forward declarations */
+
+typedef struct _EphyFavoritesMenu EphyFavoritesMenu;
+typedef struct _EphyFavoritesMenuClass EphyFavoritesMenuClass;
+typedef struct _EphyFavoritesMenuPrivate EphyFavoritesMenuPrivate;
+
+/**
+ * Editor object
+ */
+
+#define EPHY_TYPE_FAVORITES_MENU (ephy_favorites_menu_get_type())
+#define EPHY_FAVORITES_MENU(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenu))
+#define EPHY_FAVORITES_MENU_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenuClass))
+#define EPHY_IS_FAVORITES_MENU(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_FAVORITES_MENU))
+#define EPHY_IS_FAVORITES_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_FAVORITES_MENU))
+#define EPHY_FAVORITES_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenuClass))
+
+struct _EphyFavoritesMenuClass
+{
+ GObjectClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyFavoritesMenu
+{
+ GObject parent_object;
+
+ EphyFavoritesMenuPrivate *priv;
+};
+
+GType ephy_favorites_menu_get_type (void);
+
+EphyFavoritesMenu *ephy_favorites_menu_new (EphyWindow *window);
+
+void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm);
+
+void ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm,
+ const gchar *path);
+
+#endif
+
diff --git a/src/ephy-history-model.c b/src/ephy-history-model.c
new file mode 100644
index 000000000..c4e694bcd
--- /dev/null
+++ b/src/ephy-history-model.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <config.h>
+#include <gtk/gtktreeview.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libgnome/gnome-i18n.h>
+#include <time.h>
+#include <string.h>
+
+#include "ephy-node-filter.h"
+#include "ephy-history-model.h"
+#include "ephy-history.h"
+#include "ephy-tree-model-node.h"
+#include "ephy-stock-icons.h"
+#include "ephy-node.h"
+
+static void ephy_history_model_class_init (EphyHistoryModelClass *klass);
+static void ephy_history_model_init (EphyHistoryModel *model);
+static void ephy_history_model_finalize (GObject *object);
+static void ephy_history_model_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_history_model_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static guint ephy_history_model_get_flags (GtkTreeModel *tree_model);
+static int ephy_history_model_get_n_columns (GtkTreeModel *tree_model);
+static GType ephy_history_model_get_column_type (GtkTreeModel *tree_model,
+ int index);
+static gboolean ephy_history_model_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath *ephy_history_model_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static void ephy_history_model_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value);
+static gboolean ephy_history_model_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_history_model_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean ephy_history_model_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static int ephy_history_model_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_history_model_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n);
+static gboolean ephy_history_model_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+static void ephy_history_model_tree_model_init (GtkTreeModelIface *iface);
+static void root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model);
+static void root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model);
+static void root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model);
+static inline void ephy_history_model_update_node (EphyHistoryModel *model,
+ EphyNode *node,
+ int idx);
+
+struct EphyHistoryModelPrivate
+{
+ EphyNode *root;
+ EphyNode *pages;
+
+ EphyNodeFilter *filter;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ROOT,
+ PROP_PAGES,
+ PROP_FILTER
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_history_model_get_type (void)
+{
+ static GType ephy_history_model_type = 0;
+
+ if (ephy_history_model_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyHistoryModelClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_history_model_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyHistoryModel),
+ 0,
+ (GInstanceInitFunc) ephy_history_model_init
+ };
+
+ static const GInterfaceInfo tree_model_info =
+ {
+ (GInterfaceInitFunc) ephy_history_model_tree_model_init,
+ NULL,
+ NULL
+ };
+
+ ephy_history_model_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyHistoryModel",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_history_model_type,
+ GTK_TYPE_TREE_MODEL,
+ &tree_model_info);
+ }
+
+ return ephy_history_model_type;
+}
+
+static void
+ephy_history_model_class_init (EphyHistoryModelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_history_model_finalize;
+
+ object_class->set_property = ephy_history_model_set_property;
+ object_class->get_property = ephy_history_model_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root node",
+ "Root node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_PAGES,
+ g_param_spec_object ("pages",
+ "Pages node",
+ "Pages node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ g_param_spec_object ("filter",
+ "Filter object",
+ "Filter object",
+ EPHY_TYPE_NODE_FILTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_history_model_init (EphyHistoryModel *model)
+{
+ GtkWidget *dummy;
+
+ do
+ {
+ model->stamp = g_random_int ();
+ }
+ while (model->stamp == 0);
+
+ model->priv = g_new0 (EphyHistoryModelPrivate, 1);
+
+ dummy = gtk_tree_view_new ();
+
+ gtk_widget_destroy (dummy);
+}
+
+static void
+ephy_history_model_finalize (GObject *object)
+{
+ EphyHistoryModel *model;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_HISTORY_MODEL (object));
+
+ model = EPHY_HISTORY_MODEL (object);
+
+ g_return_if_fail (model->priv != NULL);
+
+ g_free (model->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_changed_cb (EphyNodeFilter *filter,
+ EphyHistoryModel *model)
+{
+ GPtrArray *kids;
+ int i;
+
+ kids = ephy_node_get_children (model->priv->root);
+
+ for (i = 0; i < kids->len; i++)
+ {
+ ephy_history_model_update_node (model,
+ g_ptr_array_index (kids, i),
+ i);
+ }
+
+ ephy_node_thaw (model->priv->root);
+}
+
+static void
+ephy_history_model_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ model->priv->root = g_value_get_object (value);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_added",
+ G_CALLBACK (root_child_added_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_removed",
+ G_CALLBACK (root_child_removed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_changed",
+ G_CALLBACK (root_child_changed_cb),
+ G_OBJECT (model),
+ 0);
+ break;
+ case PROP_PAGES:
+ model->priv->pages = g_value_get_object (value);
+ g_signal_connect_object (G_OBJECT (model->priv->pages),
+ "child_added",
+ G_CALLBACK (root_child_added_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->pages),
+ "child_removed",
+ G_CALLBACK (root_child_removed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->pages),
+ "child_changed",
+ G_CALLBACK (root_child_changed_cb),
+ G_OBJECT (model),
+ 0);
+ break;
+ case PROP_FILTER:
+ model->priv->filter = g_value_get_object (value);
+
+ if (model->priv->filter != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (model->priv->filter),
+ "changed",
+ G_CALLBACK (filter_changed_cb),
+ G_OBJECT (model),
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_history_model_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, model->priv->root);
+ break;
+ case PROP_PAGES:
+ g_value_set_object (value, model->priv->root);
+ break;
+ case PROP_FILTER:
+ g_value_set_object (value, model->priv->filter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+EphyHistoryModel *
+ephy_history_model_new (EphyNode *root,
+ EphyNode *pages,
+ EphyNodeFilter *filter)
+{
+ EphyHistoryModel *model;
+
+ model = EPHY_HISTORY_MODEL (g_object_new (EPHY_TYPE_HISTORY_MODEL,
+ "filter", filter,
+ "root", root,
+ "pages", pages,
+ NULL));
+
+ g_return_val_if_fail (model->priv != NULL, NULL);
+
+ return model;
+}
+
+static void
+ephy_history_model_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = ephy_history_model_get_flags;
+ iface->get_n_columns = ephy_history_model_get_n_columns;
+ iface->get_column_type = ephy_history_model_get_column_type;
+ iface->get_iter = ephy_history_model_get_iter;
+ iface->get_path = ephy_history_model_get_path;
+ iface->get_value = ephy_history_model_get_value;
+ iface->iter_next = ephy_history_model_iter_next;
+ iface->iter_children = ephy_history_model_iter_children;
+ iface->iter_has_child = ephy_history_model_iter_has_child;
+ iface->iter_n_children = ephy_history_model_iter_n_children;
+ iface->iter_nth_child = ephy_history_model_iter_nth_child;
+ iface->iter_parent = ephy_history_model_iter_parent;
+}
+
+static guint
+ephy_history_model_get_flags (GtkTreeModel *tree_model)
+{
+ return 0;
+}
+
+static int
+ephy_history_model_get_n_columns (GtkTreeModel *tree_model)
+{
+ return EPHY_HISTORY_MODEL_NUM_COLUMNS;
+}
+
+static GType
+ephy_history_model_get_column_type (GtkTreeModel *tree_model,
+ int index)
+{
+ g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail ((index < EPHY_HISTORY_MODEL_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
+
+ switch (index)
+ {
+ case EPHY_HISTORY_MODEL_COL_TITLE:
+ case EPHY_HISTORY_MODEL_COL_LOCATION:
+ case EPHY_HISTORY_MODEL_COL_VISITS:
+ case EPHY_HISTORY_MODEL_COL_LAST_VISIT:
+ case EPHY_HISTORY_MODEL_COL_FIRST_VISIT:
+ return G_TYPE_STRING;
+ case EPHY_HISTORY_MODEL_COL_VISIBLE:
+ return G_TYPE_BOOLEAN;
+ default:
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+ephy_history_model_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ gint *indices;
+ gint depth;
+ EphyNode *host;
+
+ g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (model), FALSE);
+
+ indices = gtk_tree_path_get_indices (path);
+ depth = gtk_tree_path_get_depth (path);
+
+ g_return_val_if_fail (depth > 0, FALSE);
+
+ iter->stamp = model->stamp;
+ host = ephy_node_get_nth_child (model->priv->root, indices [0]);
+
+ if (depth == 2 && host != NULL)
+ {
+ iter->user_data = ephy_node_get_nth_child (host, indices [1]);
+ }
+ else
+ {
+ iter->user_data = host;
+ }
+
+ if (iter->user_data == NULL)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static EphyNode *
+ensure_iter (EphyHistoryModel *model, GtkTreeIter *parent)
+{
+ EphyNode *node;
+
+ if (parent)
+ {
+ node = EPHY_NODE (parent->user_data);
+ }
+ else
+ {
+ node = model->priv->root;
+ }
+
+ return node;
+}
+
+static EphyNode *
+get_parent_node (EphyHistoryModel *model, EphyNode *node)
+{
+ int host_id;
+
+ host_id = ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID);
+
+ if (host_id < 0)
+ {
+ return model->priv->root;
+ }
+ else
+ {
+ EphyNode *host;
+ host = ephy_node_get_from_id (host_id);
+ return host;
+ }
+}
+
+static inline GtkTreePath *
+get_one_level_path_real (EphyHistoryModel *model,
+ EphyNode *node)
+{
+ GtkTreePath *retval;
+ EphyNode *my_parent;
+
+ retval = gtk_tree_path_new ();
+
+ my_parent = get_parent_node (model, node);
+
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (my_parent, node));
+
+ return retval;
+}
+
+static inline GtkTreePath *
+get_path_real (EphyHistoryModel *model,
+ EphyNode *page)
+{
+ GtkTreePath *retval;
+ EphyNode *host;
+
+ retval = gtk_tree_path_new ();
+ host = get_parent_node (model, page);
+
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (model->priv->root, host));
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (host, page));
+
+ return retval;
+}
+
+static GtkTreePath *
+ephy_history_model_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (tree_model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
+ g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (node == model->priv->root)
+ return gtk_tree_path_new ();
+
+ return get_one_level_path_real (model, node);
+}
+
+static void
+get_property_as_date (EphyNode *node,
+ int id,
+ GValue *value)
+{
+ GTime time;
+ char s[50];
+ GDate *date;
+
+ time = ephy_node_get_property_int (node, id);
+ date = g_date_new ();
+ g_date_set_time (date, time);
+ g_date_strftime (s, 50, "%c", date);
+
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, s);
+
+ g_date_free (date);
+}
+
+static void
+ephy_history_model_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_if_fail (EPHY_IS_HISTORY_MODEL (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->stamp == model->stamp);
+ g_return_if_fail (EPHY_IS_NODE (iter->user_data));
+ g_return_if_fail (column < EPHY_HISTORY_MODEL_NUM_COLUMNS);
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID) < 0 &&
+ (column == EPHY_HISTORY_MODEL_COL_LOCATION ||
+ column == EPHY_HISTORY_MODEL_COL_FIRST_VISIT ||
+ column == EPHY_HISTORY_MODEL_COL_LAST_VISIT ||
+ column == EPHY_HISTORY_MODEL_COL_VISITS))
+ {
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, "");
+ return;
+ }
+
+ switch (column)
+ {
+ case EPHY_HISTORY_MODEL_COL_TITLE:
+ ephy_node_get_property (node,
+ EPHY_NODE_PAGE_PROP_TITLE,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_LOCATION:
+ ephy_node_get_property (node,
+ EPHY_NODE_PAGE_PROP_LOCATION,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_VISITS:
+ ephy_node_get_property (node,
+ EPHY_NODE_PAGE_PROP_VISITS,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_FIRST_VISIT:
+ get_property_as_date (node,
+ EPHY_NODE_PAGE_PROP_FIRST_VISIT,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_LAST_VISIT:
+ get_property_as_date (node,
+ EPHY_NODE_PAGE_PROP_LAST_VISIT,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_VISIBLE:
+ g_value_init (value, G_TYPE_BOOLEAN);
+
+ if (model->priv->filter != NULL)
+ {
+ g_value_set_boolean (value,
+ ephy_node_filter_evaluate (model->priv->filter, node));
+ }
+ else
+ {
+ g_value_set_boolean (value, TRUE);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+ephy_history_model_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+ g_return_val_if_fail (iter->stamp == EPHY_HISTORY_MODEL (tree_model)->stamp, FALSE);
+
+ node = EPHY_NODE (iter->user_data);
+
+ iter->user_data = ephy_node_get_next_child
+ (get_parent_node (model, node), node);
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_history_model_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ node = ensure_iter (model, parent);
+
+ iter->user_data = ephy_node_get_nth_child (node, 0);
+ iter->stamp = model->stamp;
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_history_model_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+ int host_id;
+
+ node = EPHY_NODE (iter->user_data);
+ host_id = ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID);
+ if (host_id < 0)
+ {
+ return ephy_node_has_child (model->priv->root, node);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static int
+ephy_history_model_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE);
+
+ node = ensure_iter (model, iter);
+
+ return ephy_node_get_n_children (node);
+}
+
+static gboolean
+ephy_history_model_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ node = ensure_iter (model, parent);
+
+ iter->user_data = ephy_node_get_nth_child (node, n);
+ iter->stamp = model->stamp;
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_history_model_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *parent, *node;
+
+ node = EPHY_NODE (iter->user_data);
+ parent = get_parent_node (model, node);
+
+ if (parent != model->priv->root)
+ {
+ iter->user_data = parent;
+ iter->stamp = model->stamp;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+EphyNode *
+ephy_history_model_node_from_iter (EphyHistoryModel *model,
+ GtkTreeIter *iter)
+{
+ return EPHY_NODE (iter->user_data);
+}
+
+void
+ephy_history_model_iter_from_node (EphyHistoryModel *model,
+ EphyNode *node,
+ GtkTreeIter *iter)
+{
+ iter->stamp = model->stamp;
+ iter->user_data = node;
+}
+
+static inline void
+ephy_history_model_update_node (EphyHistoryModel *model,
+ EphyNode *node,
+ int idx)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_history_model_iter_from_node (model, node, &iter);
+
+ if (idx >= 0)
+ {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, idx);
+ }
+ else
+ {
+ path = get_one_level_path_real (model, node);
+ }
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model)
+{
+ GtkTreePath *path;
+
+ if (node == model->priv->root)
+ {
+ path = get_one_level_path_real (model, child);
+ }
+ else
+ {
+ path = get_path_real (model, child);
+ }
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_history_model_iter_from_node (model, child, &iter);
+
+ if (node == model->priv->root)
+ {
+ path = get_one_level_path_real (model, child);
+ }
+ else
+ {
+ path = get_path_real (model, child);
+ }
+
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model)
+{
+ ephy_history_model_update_node (model, child, -1);
+}
+
+GType
+ephy_history_model_column_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0)
+ {
+ static const GEnumValue values[] =
+ {
+ { EPHY_HISTORY_MODEL_COL_TITLE, "EPHY_HISTORY_MODEL_COL_TITLE", "title" },
+ { EPHY_HISTORY_MODEL_COL_LOCATION, "EPHY_HISTORY_MODEL_COL_LOCATION", "location" },
+ { EPHY_HISTORY_MODEL_COL_VISITS, "EPHY_HISTORY_MODEL_COL_VISITS", "visits" },
+ { EPHY_HISTORY_MODEL_COL_FIRST_VISIT, "EPHY_HISTORY_MODEL_COL_FIRST_VISIT", "last_visit" },
+ { EPHY_HISTORY_MODEL_COL_LAST_VISIT, "EPHY_HISTORY_MODEL_COL_LAST_VISIT", "last_visit" },
+ { EPHY_HISTORY_MODEL_COL_VISIBLE, "EPHY_HISTORY_MODEL_COL_FIRST_VISIT", "first_visit" },
+
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("EphyHistoryModelColumn", values);
+ }
+
+ return etype;
+}
+
diff --git a/src/ephy-history-model.h b/src/ephy-history-model.h
new file mode 100644
index 000000000..6ff0058de
--- /dev/null
+++ b/src/ephy-history-model.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __EPHY_HISTORY_MODEL_H
+#define __EPHY_HISTORY_MODEL_H
+
+#include <gtk/gtktreemodel.h>
+
+#include "ephy-node.h"
+#include "ephy-node-filter.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_HISTORY_MODEL (ephy_history_model_get_type ())
+#define EPHY_HISTORY_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModel))
+#define EPHY_HISTORY_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModelClass))
+#define EPHY_IS_HISTORY_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_HISTORY_MODEL))
+#define EPHY_IS_HISTORY_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_HISTORY_MODEL))
+#define EPHY_HISTORY_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModelClass))
+
+typedef enum
+{
+ EPHY_HISTORY_MODEL_COL_TITLE,
+ EPHY_HISTORY_MODEL_COL_LOCATION,
+ EPHY_HISTORY_MODEL_COL_VISITS,
+ EPHY_HISTORY_MODEL_COL_FIRST_VISIT,
+ EPHY_HISTORY_MODEL_COL_LAST_VISIT,
+ EPHY_HISTORY_MODEL_COL_VISIBLE,
+ EPHY_HISTORY_MODEL_NUM_COLUMNS
+} EphyHistoryModelColumn;
+
+GType ephy_history_model_column_get_type (void);
+
+#define EPHY_TYPE_HISTORY_MODEL_COLUMN (ephy_history_model_column_get_type ())
+
+typedef struct EphyHistoryModelPrivate EphyHistoryModelPrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyHistoryModelPrivate *priv;
+
+ int stamp;
+} EphyHistoryModel;
+
+typedef struct
+{
+ GObjectClass parent;
+} EphyHistoryModelClass;
+
+GType ephy_history_model_get_type (void);
+
+EphyHistoryModel *ephy_history_model_new (EphyNode *root,
+ EphyNode *pages,
+ EphyNodeFilter *filter);
+
+EphyNode *ephy_history_model_node_from_iter (EphyHistoryModel *model,
+ GtkTreeIter *iter);
+
+void ephy_history_model_iter_from_node (EphyHistoryModel *model,
+ EphyNode *node,
+ GtkTreeIter *iter);
+
+G_END_DECLS
+
+#endif /* EPHY_HISTORY_MODEL_H */
diff --git a/src/ephy-main.c b/src/ephy-main.c
new file mode 100644
index 000000000..0a0093974
--- /dev/null
+++ b/src/ephy-main.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2000-2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ephy-shell.h"
+#include "ephy-automation.h"
+#include "ephy-window.h"
+#include "EphyAutomation.h"
+
+#include <libbonoboui.h>
+#include <libgnome/gnome-program.h>
+#include <libgnomeui/gnome-ui-init.h>
+#include <libgnomeui/gnome-window-icon.h>
+#include <libgnomevfs/gnome-vfs-init.h>
+#include <glade/glade-init.h>
+
+#define EPHY_FACTORY_OAFIID "OAFIID:GNOME_Epiphany_Automation_Factory"
+
+static gboolean
+ephy_main_automation_init (void);
+static gint
+ephy_main_translate_url_arguments (poptContext context, gchar ***urls);
+static gboolean
+ephy_main_start (gpointer data);
+
+GnomeProgram *program;
+CORBA_Environment corba_env; /* Global for downloader */
+static gboolean open_in_existing = FALSE; /* load in existing window? */
+static gboolean open_in_new_tab = FALSE; /* force open in a new tab? */
+static gboolean noraise = FALSE; /* no raise */
+static gboolean open_in_new_window = FALSE; /* force open in a new window? */
+static gboolean open_fullscreen = FALSE; /* open ephy in full screen ? */
+static gchar *session_filename = NULL; /* the session filename */
+static gchar *geometry_string = NULL; /* the geometry string */
+static gchar *bookmark_url = NULL; /* the temp bookmark to add */
+static gboolean close_option = FALSE; /* --close */
+static gboolean quit_option = FALSE; /* --quit */
+static gboolean ephy_server_mode = FALSE;
+static gboolean open_as_nautilus_view = FALSE;
+
+static BonoboObject *automation_object;
+static gint n_urls;
+static gchar **url;
+static gboolean first_instance;
+
+/* command line argument parsing structure */
+static struct poptOption popt_options[] =
+{
+ { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &bonobo_activation_popt_options, 0, NULL,
+ NULL },
+ { "new-tab", 'n', POPT_ARG_NONE, &open_in_new_tab, 0,
+ N_("Open a new tab in an existing Ephy window"),
+ NULL },
+ { "new-window", 'w', POPT_ARG_NONE, &open_in_new_window, 0,
+ N_("Open a new window in an existing Ephy process"),
+ NULL },
+ { "noraise", '\0', POPT_ARG_NONE, &noraise, 0,
+ N_("Do not raise the window when opening a page in an existing Ephy process"),
+ NULL },
+ { "fullscreen", 'f', POPT_ARG_NONE, &open_fullscreen, 0,
+ N_("Run Ephy in full screen mode"),
+ NULL },
+ { "existing", 'x', POPT_ARG_NONE, &open_in_existing, 0,
+ N_("Attempt to load URL in existing Ephy window"),
+ NULL },
+ { "load-session", 'l', POPT_ARG_STRING, &session_filename, 0,
+ N_("Load the given session file"),
+ N_("FILE") },
+ { "server", 's', POPT_ARG_NONE, &ephy_server_mode, 0,
+ N_("Don't open any windows; instead act as a server "
+ "for quick startup of new Ephy instances"),
+ NULL },
+ { "add-bookmark", 't', POPT_ARG_STRING, &bookmark_url,
+ 0, N_("Add a bookmark (don't open any window)"),
+ N_("URL")},
+ { "geometry", 'g', POPT_ARG_STRING, &geometry_string,
+ 0, N_("Create the initial window with the given geometry.\n"
+ "see X(1) for the GEOMETRY format"),
+ N_("GEOMETRY")},
+ { "close", 'c', POPT_ARG_NONE, &close_option, 0,
+ N_("Close all Ephy windows"),
+ NULL },
+ { "quit", 'q', POPT_ARG_NONE, &quit_option, 0,
+ N_("Same as --close, but exits server mode too"),
+ NULL },
+ { "nautilus-view", 'v', POPT_ARG_NONE, &open_as_nautilus_view, 0,
+ N_("Used internally by the nautilus view"),
+ NULL },
+
+ /* terminator, must be last */
+ { NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+int
+main (int argc, char *argv[])
+{
+ poptContext context;
+ GValue context_as_value = { 0 };
+ GnomeProgram *program;
+
+#ifdef ENABLE_NLS
+ /* Initialize the i18n stuff */
+ bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ textdomain(GETTEXT_PACKAGE);
+#endif
+
+ program = gnome_program_init (PACKAGE, VERSION,
+ LIBGNOMEUI_MODULE, argc, argv,
+ GNOME_PARAM_POPT_TABLE, popt_options,
+ GNOME_PARAM_HUMAN_READABLE_NAME, _("Ephy"),
+ GNOME_PARAM_APP_DATADIR, DATADIR,
+ NULL);
+
+ g_object_get_property (G_OBJECT (program),
+ GNOME_PARAM_POPT_CONTEXT,
+ g_value_init (&context_as_value, G_TYPE_POINTER));
+
+ context = g_value_get_pointer (&context_as_value);
+
+ /* load arguments that aren't regular options (urls to load) */
+ n_urls = ephy_main_translate_url_arguments (context, &url);
+
+ first_instance = ephy_main_automation_init ();
+
+ if (first_instance)
+ {
+ gnome_vfs_init ();
+
+ glade_gnome_init ();
+
+ gnome_window_icon_set_default_from_file (PIXMAP_DIR "/ephy.png");
+
+ ephy_shell_new ();
+
+ g_idle_add ((GSourceFunc) ephy_main_start, NULL);
+
+ bonobo_main ();
+
+ gnome_vfs_shutdown ();
+ }
+
+ return 0;
+}
+
+static gboolean
+ephy_main_start (gpointer data)
+{
+ GNOME_EphyAutomation gaserver;
+ int i;
+
+ CORBA_exception_init (&corba_env);
+
+ gaserver = bonobo_activation_activate_from_id ("OAFIID:GNOME_Epiphany_Automation",
+ 0, NULL, &corba_env);
+
+ if (gaserver == NULL)
+ {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new
+ (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Ephy can't be used now. "
+ "Running the command \"bonobo-slay\" "
+ "from the console may fix the problem. If not, "
+ "you can try rebooting the computer or "
+ "installing Ephy again.\n\n"
+ "Bonobo couldn't locate the GNOME_Epiphany_Automation.server. ");
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ }
+ /* FIXME ephy --server doesnt work when not first istance */
+ /* Server mode */
+ else if (ephy_server_mode)
+ {
+ g_object_ref (G_OBJECT(ephy_shell));
+ }
+ /* load the session if requested */
+ else if (session_filename)
+ {
+ GNOME_EphyAutomation_loadSession
+ (gaserver, session_filename, &corba_env);
+ }
+ /* if found and we're given a bookmark to add... */
+ else if (bookmark_url != NULL)
+ {
+ GNOME_EphyAutomation_addBookmark
+ (gaserver, bookmark_url, &corba_env);
+ }
+ else if (close_option || quit_option)
+ {
+ GNOME_EphyAutomation_quit
+ (gaserver, quit_option, &corba_env);
+ }
+ /* provided with urls? */
+ else if (n_urls == 0 &&
+ !open_as_nautilus_view)
+ {
+ /* no, open a default window */
+ GNOME_EphyAutomation_loadurl
+ (gaserver, "",
+ geometry_string ?
+ geometry_string : "",
+ open_fullscreen,
+ open_in_existing,
+ open_in_new_window,
+ open_in_new_tab,
+ !noraise,
+ &corba_env);
+ }
+ else
+ {
+ /* open all of the urls */
+ for (i = 0; i < n_urls; i++)
+ {
+ GNOME_EphyAutomation_loadurl
+ (gaserver, url[i],
+ geometry_string ?
+ geometry_string : "",
+ open_fullscreen,
+ open_in_existing,
+ open_in_new_window,
+ open_in_new_tab,
+ !noraise,
+ &corba_env);
+ }
+ }
+
+ /* Unref so it will exit if no more used */
+ if (first_instance)
+ {
+ g_object_unref (G_OBJECT(ephy_shell));
+ }
+
+ if (gaserver)
+ {
+ bonobo_object_release_unref (gaserver, &corba_env);
+ }
+
+ CORBA_exception_free (&corba_env);
+
+ return FALSE;
+}
+
+static gboolean
+ephy_main_automation_init (void)
+{
+ CORBA_Object factory;
+
+ factory = bonobo_activation_activate_from_id
+ (EPHY_FACTORY_OAFIID,
+ Bonobo_ACTIVATION_FLAG_EXISTING_ONLY,
+ NULL, NULL);
+
+ if (!factory)
+ {
+ automation_object = ephy_automation_new ();
+ return TRUE;
+ }
+ else
+ {
+ ephy_main_start (NULL);
+ g_message (_("Ephy already running, using existing process"));
+ return FALSE;
+ }
+}
+
+/**
+ * translate_url_arguments: gather URL arguments and expand them fully
+ * with realpath if they're filenames
+ */
+static gint
+ephy_main_translate_url_arguments (poptContext context, gchar ***urls)
+{
+ gchar buffer[PATH_MAX];
+ gchar **args;
+ gint i, n;
+
+ /* any context remaining? */
+ if (context == NULL)
+ {
+ *urls = NULL;
+ return 0;
+ }
+
+ /* get the args and check */
+ args = (gchar **) poptGetArgs (context);
+ if (args == NULL)
+ {
+ poptFreeContext (context);
+ *urls = NULL;
+ return 0;
+ }
+
+ /* count args */
+ for (n = 0; args[n] != NULL; n++)
+ /* nothing */;
+
+ /* allocate pointer array */
+ *urls = g_new0 (gchar *, n + 1);
+
+ /* translate each one */
+ for (i = 0; i < n; i++)
+ {
+ /* try to expand as files */
+ if (realpath (args[i], buffer) != NULL)
+ {
+ (*urls)[i] = g_strconcat ("file://", buffer, NULL);
+ }
+ else
+ {
+ (*urls)[i] = g_strdup (args[i]);
+ }
+ }
+ poptFreeContext (context);
+ (*urls)[i] = NULL;
+
+ /* return the number of urls */
+ return n;
+}
diff --git a/src/ephy-nautilus-view.c b/src/ephy-nautilus-view.c
new file mode 100644
index 000000000..f7a0ff867
--- /dev/null
+++ b/src/ephy-nautilus-view.c
@@ -0,0 +1,954 @@
+/*
+ * Copyright (C) 2001, 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <libgnome/gnome-macros.h>
+#include <bonobo/bonobo-zoomable.h>
+#include <bonobo/bonobo-ui-util.h>
+#include <string.h>
+#include "ephy-embed-popup-control.h"
+#include "ephy-nautilus-view.h"
+#include "ephy-embed.h"
+#include "ephy-embed-utils.h"
+#include "find-dialog.h"
+#include "print-dialog.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+#define DEBUG_MSG(x) g_print x
+//#define DEBUG_MSG(x)
+
+static void gnv_embed_location_cb (EphyEmbed *embed,
+ EphyNautilusView *view);
+static void gnv_embed_title_cb (EphyEmbed *embed,
+ EphyNautilusView *view);
+static void gnv_embed_new_window_cb (EphyEmbed *embed,
+ EphyEmbed **new_embed,
+ EmbedChromeMask chromemask,
+ EphyNautilusView *view);
+static void gnv_embed_link_message_cb (EphyEmbed *embed,
+ const char *message,
+ EphyNautilusView *view);
+static gint gnv_embed_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyNautilusView *view);
+static void gnv_embed_zoom_change_cb (EphyNautilusView *embed,
+ guint new_zoom,
+ EphyNautilusView *view);
+
+
+static void gnv_load_location_cb (EphyNautilusView *view,
+ const char *location,
+ gpointer user_data);
+static void gnv_stop_loading_cb (EphyNautilusView *view,
+ gpointer user_data);
+static void gnv_bonobo_control_activate_cb (BonoboControl *control,
+ gboolean state,
+ EphyNautilusView *view);
+
+/* zoomable */
+static void gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable,
+ float level,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_to_default_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+/* commands */
+static void gnv_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname);
+static void gnv_cmd_file_print (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname);
+static void gnv_cmd_edit_find (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname);
+
+
+/* popups */
+static EphyNautilusView *gnv_view_from_popup (EphyEmbedPopup *popup);
+
+static void gnv_popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+
+static float preferred_zoom_levels[] = {
+ 0.2, 0.4, 0.6, 0.8,
+ 1.0, 1.2, 1.4, 1.6, 1.8,
+ 2.0, 2.2, 2.4, 2.6, 2.8,
+ 3.0, 3.2, 3.4, 3.6, 3.8,
+ 4.0, 4.2, 4.4, 4.6, 4.8,
+ 5.0, 5.2, 5.4, 5.6, 5.8,
+ 6.0, 6.2, 6.4, 6.6, 6.8,
+ 7.0, 7.2, 7.4, 7.6, 7.8,
+ 8.0, 8.2, 8.4, 8.6, 8.8,
+ 9.0, 9.2, 9.4, 9.6, 9.8,
+};
+
+static const gchar *preferred_zoom_level_names[] = {
+ "20%", "40%", "60%", "80%",
+ "100%", "120%", "140%", "160%", "180%",
+ "200%", "220%", "240%", "260%", "280%",
+ "300%", "320%", "340%", "360%", "380%",
+ "400%", "420%", "440%", "460%", "480%",
+ "500%", "520%", "540%", "560%", "580%",
+ "600%", "620%", "640%", "660%", "680%",
+ "700%", "720%", "740%", "760%", "780%",
+ "800%", "820%", "840%", "860%", "880%",
+ "900%", "920%", "940%", "960%", "980%",
+};
+#define NUM_ZOOM_LEVELS (sizeof (preferred_zoom_levels) / sizeof (float))
+
+struct EphyNautilusViewPrivate {
+ EphyEmbed *embed;
+ char *title;
+ char *location;
+ int load_percent;
+
+ /*
+ BonoboPropertyBag *property_bag;
+ */
+
+ EphyEmbedPopupControl *popup;
+ BonoboUIComponent *popup_ui;
+ BonoboControl *control;
+ BonoboUIComponent *ui;
+ BonoboZoomable *zoomable;
+
+ EphyDialog *find_dialog;
+};
+
+static BonoboUIVerb ephy_popup_verbs [] = {
+ BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_new_window),
+ BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_image_in_new_window),
+ BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_frame_in_new_window),
+
+ BONOBO_UI_VERB_END
+};
+
+BonoboUIVerb ephy_verbs [] = {
+ BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn) gnv_cmd_file_print),
+ BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn) gnv_cmd_edit_find),
+ BONOBO_UI_VERB_END
+};
+
+#define CHARSET_MENU_PATH "/menu/View/Encoding"
+
+
+BONOBO_CLASS_BOILERPLATE (EphyNautilusView, ephy_nautilus_view,
+ NautilusView, NAUTILUS_TYPE_VIEW)
+
+static void
+ephy_nautilus_view_instance_init (EphyNautilusView *view)
+{
+ GtkWidget *w;
+ EphyNautilusViewPrivate *p = g_new0 (EphyNautilusViewPrivate, 1);
+
+ view->priv = p;
+ view->priv->embed = ephy_embed_new (G_OBJECT (ephy_shell_get_embed_shell (ephy_shell)));
+
+ g_object_ref (G_OBJECT (ephy_shell));
+
+ g_signal_connect (view->priv->embed, "ge_link_message",
+ GTK_SIGNAL_FUNC (gnv_embed_link_message_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_location",
+ GTK_SIGNAL_FUNC (gnv_embed_location_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_title",
+ GTK_SIGNAL_FUNC (gnv_embed_title_cb),
+ view);
+/*
+ g_signal_connect (view->priv->embed, "ge_js_status",
+ GTK_SIGNAL_FUNC (gnv_embed_js_status_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_progress",
+ GTK_SIGNAL_FUNC (gnv_embed_progress_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_net_state",
+ GTK_SIGNAL_FUNC (gnv_embed_net_state_cb),
+ view);
+*/
+ g_signal_connect (view->priv->embed, "ge_new_window",
+ GTK_SIGNAL_FUNC (gnv_embed_new_window_cb),
+ view);
+/*
+ g_signal_connect (view->priv->embed, "ge_visibility",
+ GTK_SIGNAL_FUNC (gnv_embed_visibility_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_destroy_brsr",
+ GTK_SIGNAL_FUNC (gnv_embed_destroy_brsr_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_open_uri",
+ GTK_SIGNAL_FUNC (gnv_embed_open_uri_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_size_to",
+ GTK_SIGNAL_FUNC (gnv_embed_size_to_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_dom_mouse_click",
+ GTK_SIGNAL_FUNC (gnv_embed_dom_mouse_click_cb),
+ view);
+*/
+ g_signal_connect (view->priv->embed, "ge_dom_mouse_down",
+ GTK_SIGNAL_FUNC (gnv_embed_dom_mouse_down_cb),
+ view);
+/*
+ g_signal_connect (view->priv->embed, "ge_security_change",
+ GTK_SIGNAL_FUNC (gnv_embed_security_change_cb),
+ view);
+*/
+ g_signal_connect (view->priv->embed, "ge_zoom_change",
+ GTK_SIGNAL_FUNC (gnv_embed_zoom_change_cb),
+ view);
+
+ w = GTK_WIDGET (view->priv->embed);
+ gtk_widget_show (w);
+
+ nautilus_view_construct (NAUTILUS_VIEW (view), w);
+
+ g_signal_connect (G_OBJECT (view), "load_location",
+ G_CALLBACK (gnv_load_location_cb), NULL);
+
+ g_signal_connect (G_OBJECT (view), "stop_loading",
+ G_CALLBACK (gnv_stop_loading_cb), NULL);
+
+ g_signal_connect (G_OBJECT (nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view))),
+ "activate",
+ G_CALLBACK (gnv_bonobo_control_activate_cb), view);
+
+ view->priv->zoomable = bonobo_zoomable_new ();
+ bonobo_object_add_interface (BONOBO_OBJECT (view),
+ BONOBO_OBJECT (view->priv->zoomable));
+
+ bonobo_zoomable_set_parameters_full (view->priv->zoomable,
+ 1.0,
+ preferred_zoom_levels [0],
+ preferred_zoom_levels [NUM_ZOOM_LEVELS - 1],
+ FALSE, FALSE, TRUE,
+ preferred_zoom_levels,
+ preferred_zoom_level_names,
+ NUM_ZOOM_LEVELS);
+
+ bonobo_object_add_interface (BONOBO_OBJECT (view),
+ BONOBO_OBJECT (view->priv->zoomable));
+
+ g_signal_connect (view->priv->zoomable, "set_zoom_level",
+ G_CALLBACK (gnv_zoomable_set_zoom_level_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_in",
+ G_CALLBACK (gnv_zoomable_zoom_in_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_out",
+ G_CALLBACK (gnv_zoomable_zoom_out_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_to_fit",
+ G_CALLBACK (gnv_zoomable_zoom_to_fit_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_to_default",
+ G_CALLBACK (gnv_zoomable_zoom_to_default_cb), view);
+
+ p->control = nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view));
+
+ p->popup_ui = bonobo_control_get_popup_ui_component (p->control);
+ g_assert (BONOBO_IS_UI_COMPONENT (p->popup_ui));
+ bonobo_ui_util_set_ui (p->popup_ui, DATADIR,
+ "nautilus-ephy-view-ui.xml",
+ "EphyNutilusView", NULL);
+ p->popup = ephy_embed_popup_control_new (p->control);
+ ephy_embed_popup_connect_verbs (EPHY_EMBED_POPUP (p->popup), p->popup_ui);
+ g_object_set_data (G_OBJECT (p->popup), "NautilisView", view);
+
+ bonobo_ui_component_add_verb_list_with_data (p->popup_ui, ephy_popup_verbs, p->popup);
+}
+
+/**
+ * Returns a new EphyNautilusView as a BonoboObject
+ **/
+BonoboObject *
+ephy_nautilus_view_new_component (EphyShell *gs)
+{
+ EphyNautilusView *view;
+ view = EPHY_NAUTILUS_VIEW (g_object_new (EPHY_TYPE_NAUTILUS_VIEW, NULL));
+ return BONOBO_OBJECT (view);
+}
+
+static void
+ephy_nautilus_view_finalize (GObject *object)
+{
+ EphyNautilusView *view = EPHY_NAUTILUS_VIEW (object);
+ EphyNautilusViewPrivate *p = view->priv;
+
+ if (p->find_dialog)
+ {
+ g_object_unref (p->find_dialog);
+ }
+
+ g_object_unref (p->popup);
+
+ g_free (p->title);
+ g_free (p->location);
+ g_free (p);
+
+ GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+
+ g_object_unref (G_OBJECT (ephy_shell));
+}
+
+static void
+ephy_nautilus_view_class_init (EphyNautilusViewClass *class)
+{
+ G_OBJECT_CLASS (class)->finalize = ephy_nautilus_view_finalize;
+}
+
+
+
+static gint
+gnv_embed_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyNautilusView *view)
+{
+ EphyNautilusViewPrivate *p = view->priv;
+ int button;
+ EmbedEventContext context;
+
+ ephy_embed_event_get_mouse_button (event, &button);
+ ephy_embed_event_get_context (event, &context);
+
+ if (button == 2)
+ {
+ ephy_embed_popup_set_event (EPHY_EMBED_POPUP (p->popup), event);
+ ephy_embed_popup_show (EPHY_EMBED_POPUP (p->popup), embed);
+ return TRUE;
+
+ }
+ else if (button == 1
+ && (context & EMBED_CONTEXT_LINK))
+ {
+ GValue *value;
+ const gchar *url;
+ ephy_embed_event_get_property (event, "link", &value);
+ url = g_value_get_string (value);
+
+ g_return_val_if_fail (url, FALSE);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ url, NULL);
+ }
+
+ return FALSE;
+}
+
+static void
+gnv_embed_link_message_cb (EphyEmbed *embed, const char *message, EphyNautilusView *view)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ g_return_if_fail (message != NULL);
+
+ nautilus_view_report_status (NAUTILUS_VIEW (view), message);
+}
+
+static void
+gnv_embed_location_cb (EphyEmbed *embed, EphyNautilusView *view)
+{
+ EphyNautilusViewPrivate *p;
+ const gchar *prefixes_to_ignore[] =
+ {
+ "about:",
+ "javascript:",
+ NULL
+ };
+ int i = 0;
+ gchar *new_uri;
+
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ p = view->priv;
+ g_return_if_fail (view->priv->embed == embed);
+
+ ephy_embed_get_location (embed, TRUE, FALSE,
+ &new_uri);
+
+ g_return_if_fail (new_uri != NULL);
+
+
+ /* don't inform nautilus about uris that it can't understand */
+ while (prefixes_to_ignore[i] != NULL)
+ {
+ if (!strncmp (prefixes_to_ignore[i], new_uri, strlen (prefixes_to_ignore[i])))
+ {
+ g_free (new_uri);
+ return;
+ }
+ ++i;
+ }
+
+ nautilus_view_report_location_change (NAUTILUS_VIEW (view), new_uri, NULL, new_uri);
+
+ /* TODO, FIXME
+ nautilus_view_report_redirect (view, p->location, new_uri, NULL, new_uri);
+ */
+
+
+ g_free (p->location);
+ p->location = new_uri;
+
+
+}
+
+static void
+gnv_embed_title_cb (EphyEmbed *embed, EphyNautilusView *view)
+{
+ EphyNautilusViewPrivate *p;
+
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ p = view->priv;
+ g_return_if_fail (view->priv->embed == embed);
+
+ g_free (p->title);
+ ephy_embed_get_title (embed, &p->title);
+
+ nautilus_view_set_title (NAUTILUS_VIEW (view), p->title);
+}
+
+static void
+gnv_load_location_cb (EphyNautilusView *view, const char *location, gpointer user_data)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ g_return_if_fail (location != NULL);
+
+ nautilus_view_report_load_underway (NAUTILUS_VIEW (view));
+ ephy_embed_load_url (view->priv->embed, location);
+
+}
+
+static void
+gnv_stop_loading_cb (EphyNautilusView *view, gpointer user_data)
+{
+}
+
+static void
+gnv_embed_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
+ EmbedChromeMask chromemask, EphyNautilusView *view)
+{
+ EphyTab *new_tab;
+ EphyWindow *window;
+
+ window = ephy_window_new ();
+ if (!(chromemask & EMBED_CHROME_OPENASCHROME))
+ {
+ ephy_window_set_chrome (window,
+ chromemask |
+ EMBED_CHROME_OPENASPOPUP);
+ }
+ new_tab = ephy_tab_new ();
+ ephy_window_add_tab (window, new_tab, FALSE);
+
+ *new_embed = ephy_tab_get_embed (new_tab);
+}
+
+
+static void
+gnv_bonobo_control_activate_cb (BonoboControl *control, gboolean state, EphyNautilusView *view)
+{
+ if (state)
+ {
+ EphyNautilusViewPrivate *p = view->priv;
+
+ p->ui = nautilus_view_set_up_ui (NAUTILUS_VIEW (view), DATADIR,
+ "nautilus-ephy-view-ui.xml", "EphyNutilusView");
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui));
+
+ ephy_embed_utils_build_charsets_submenu (p->ui,
+ CHARSET_MENU_PATH,
+ (BonoboUIVerbFn) gnv_cmd_set_charset,
+ view);
+
+ bonobo_ui_component_add_verb_list_with_data (p->ui, ephy_verbs, view);
+ }
+}
+
+static EphyNautilusView *
+gnv_view_from_popup (EphyEmbedPopup *popup)
+{
+ return g_object_get_data (G_OBJECT (popup), "NautilisView");
+}
+
+
+static void
+gnv_popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyNautilusView *view;
+ GValue *value;
+
+ view = gnv_view_from_popup (popup);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "link", &value);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ g_value_get_string (value), NULL);
+}
+
+static void
+gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyNautilusView *view;
+ GValue *value;
+
+ view = gnv_view_from_popup (popup);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "image", &value);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ g_value_get_string (value), NULL);
+}
+
+static void
+gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyNautilusView *view;
+ gchar *location;
+
+ view = gnv_view_from_popup (popup);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_get_location (view->priv->embed, FALSE, FALSE, &location);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ location, NULL);
+}
+
+void
+gnv_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname)
+{
+ EphyNautilusView *view = data->data;
+ EphyNautilusViewPrivate *p;
+
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+
+ p = view->priv;
+
+ DEBUG_MSG ((data->encoding));
+ ephy_embed_set_charset (p->embed, data->encoding);
+}
+
+static void
+gnv_cmd_file_print (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+ EphyNautilusViewPrivate *p = view->priv;
+
+ dialog = print_dialog_new (p->embed, NULL);
+
+ //g_signal_connect (G_OBJECT(dialog),
+ // "preview",
+ // G_CALLBACK (print_dialog_preview_cb),
+ // window);
+
+ ephy_dialog_set_modal (dialog, TRUE);
+ ephy_dialog_show (dialog);
+
+}
+
+static void
+gnv_cmd_edit_find (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname)
+{
+ EphyNautilusViewPrivate *p = view->priv;
+
+ if (!p->find_dialog)
+ {
+ p->find_dialog = find_dialog_new (p->embed);
+ }
+
+ ephy_dialog_show (p->find_dialog);
+}
+
+
+/* zoomable */
+static void
+gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable,
+ float level,
+ EphyNautilusView *view)
+{
+ gint zoom = level * 100;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ if (zoom < 10) return;
+ if (zoom > 1000) return;
+ ephy_embed_zoom_set (view->priv->embed, zoom, TRUE);
+}
+
+static void
+gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ gint zoom;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ ephy_embed_zoom_get (view->priv->embed, &zoom);
+ if (zoom > 990) return;
+ ephy_embed_zoom_set (view->priv->embed, zoom + 10, TRUE);
+}
+
+static void
+gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ gint zoom;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ ephy_embed_zoom_get (view->priv->embed, &zoom);
+ if (zoom < 20) return;
+ ephy_embed_zoom_set (view->priv->embed, zoom - 10, TRUE);
+}
+
+static void
+gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ gnv_zoomable_zoom_to_default_cb (zoomable, view);
+}
+
+static void
+gnv_zoomable_zoom_to_default_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ ephy_embed_zoom_set (view->priv->embed, 100, TRUE);
+}
+
+static void
+gnv_embed_zoom_change_cb (EphyNautilusView *embed,
+ guint new_zoom,
+ EphyNautilusView *view)
+{
+ float flevel;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+
+ flevel = ((float) new_zoom) / 100.0;
+
+ bonobo_zoomable_report_zoom_level_changed (view->priv->zoomable,
+ flevel, NULL);
+
+}
+
+
+#ifdef IM_TOO_LAZY_TO_MOVE_THIS_TO_ANOTHER_FILE
+
+
+/* property bag properties */
+enum {
+ ICON_NAME,
+ COMPONENT_INFO
+};
+
+
+static void
+get_bonobo_properties (BonoboPropertyBag *bag,
+ BonoboArg *arg,
+ guint arg_id,
+ CORBA_Environment *ev,
+ gpointer callback_data)
+{
+ EphyNautilusView *content_view;
+
+ content_view = (EphyNautilusView*) callback_data;
+
+ switch (arg_id) {
+ case ICON_NAME:
+ if (!strncmp (content_view->priv->uri, "man:", 4)) {
+ BONOBO_ARG_SET_STRING (arg, "manual");
+ } else if (!strncmp (content_view->priv->uri, "http:", 5)) {
+ BONOBO_ARG_SET_STRING (arg, "i-web");
+ } else if (!strncmp (content_view->priv->uri, "https:", 6)) {
+ /* FIXME: put a nice icon for secure sites */
+ BONOBO_ARG_SET_STRING (arg, "i-web");
+ } else {
+ BONOBO_ARG_SET_STRING (arg, "");
+ }
+ break;
+
+ case COMPONENT_INFO:
+ BONOBO_ARG_SET_STRING (arg, "");
+ break;
+
+ default:
+ g_warning ("Unhandled arg %d", arg_id);
+ break;
+ }
+}
+
+/* there are no settable properties, so complain if someone tries to set one */
+static void
+set_bonobo_properties (BonoboPropertyBag *bag,
+ const BonoboArg *arg,
+ guint arg_id,
+ CORBA_Environment *ev,
+ gpointer callback_data)
+{
+ g_warning ("Bad Property set on view: property ID %d",
+ arg_id);
+}
+
+static void
+ephy_nautilus_view_initialize (EphyNautilusView *view)
+{
+
+
+#ifdef NOT_PORTED
+ bonobo_control_set_properties (nautilus_view_get_bonobo_control (view->priv->nautilus_view),
+ view->priv->property_bag);
+#endif
+ bonobo_property_bag_add (view->priv->property_bag, "icon_name", ICON_NAME,
+ BONOBO_ARG_STRING, NULL,
+ _("name of icon for the mozilla view"), 0);
+ bonobo_property_bag_add (view->priv->property_bag, "summary_info", COMPONENT_INFO,
+ BONOBO_ARG_STRING, NULL,
+ _("mozilla summary info"), 0);
+}
+
+
+ /* free the property bag */
+ if (view->priv->property_bag != NULL) {
+ bonobo_object_unref (BONOBO_OBJECT (view->priv->property_bag));
+ view->priv->property_bag = NULL;
+ }
+
+}
+
+
+
+void
+ephy_nautilus_view_report_load_progress (EphyNautilusView *view,
+ double value)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+
+ if (value < 0.0) value = 0.0;
+ if (value > 1.0) value = 1.0;
+
+ nautilus_view_report_load_progress (view->priv->nautilus_view, value);
+}
+
+/***********************************************************************************/
+
+/**
+ * vfs_open_cb
+ *
+ * Callback for gnome_vfs_async_open. Attempt to read data from handle
+ * and pass to mozilla streaming callback.
+ *
+ **/
+static void
+vfs_open_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ EphyNautilusView *view = data;
+
+ DEBUG_MSG (("+%s GnomeVFSResult: %u\n", G_GNUC_FUNCTION, (unsigned)result));
+
+ if (result != GNOME_VFS_OK)
+ {
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed));
+ /* NOTE: the view may go away after a call to report_load_failed */
+ DEBUG_MSG ((">nautilus_view_report_load_failed\n"));
+ nautilus_view_report_load_failed (view->priv->nautilus_view);
+ } else {
+ if (view->priv->vfs_read_buffer == NULL) {
+ view->priv->vfs_read_buffer = g_malloc (VFS_READ_BUFFER_SIZE);
+ }
+ gtk_moz_embed_open_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed), "file:///", "text/html");
+ gnome_vfs_async_read (handle, view->priv->vfs_read_buffer, VFS_READ_BUFFER_SIZE, vfs_read_cb, view);
+ }
+ DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION));
+}
+
+/**
+ * vfs_read_cb:
+ *
+ * Read data from buffer and copy into mozilla stream.
+ **/
+
+static void
+vfs_read_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer buffer,
+ GnomeVFSFileSize bytes_requested,
+ GnomeVFSFileSize bytes_read,
+ gpointer data)
+{
+ EphyNautilusView *view = data;
+
+ DEBUG_MSG (("+%s %ld/%ld bytes\n", G_GNUC_FUNCTION, (long)bytes_requested, (long) bytes_read));
+
+ if (bytes_read != 0) {
+ gtk_moz_embed_append_data (GTK_MOZ_EMBED (view->priv->embed->mozembed), buffer, bytes_read);
+ }
+
+ if (bytes_read == 0 || result != GNOME_VFS_OK) {
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed));
+ view->priv->vfs_handle = NULL;
+ g_free (view->priv->vfs_read_buffer);
+ view->priv->vfs_read_buffer = NULL;
+
+ gnome_vfs_async_close (handle, (GnomeVFSAsyncCloseCallback) gtk_true, NULL);
+
+ DEBUG_MSG ((">nautilus_view_report_load_complete\n"));
+ nautilus_view_report_load_complete (view->priv->nautilus_view);
+
+ DEBUG_MSG (("=%s load complete\n", G_GNUC_FUNCTION));
+ } else {
+ gnome_vfs_async_read (handle, view->priv->vfs_read_buffer, VFS_READ_BUFFER_SIZE, vfs_read_cb, view);
+ }
+
+ DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION));
+}
+
+/***********************************************************************************/
+
+static void
+cancel_pending_vfs_operation (EphyNautilusView *view)
+{
+ if (view->priv->vfs_handle != NULL) {
+ gnome_vfs_async_cancel (view->priv->vfs_handle);
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed));
+ }
+
+ view->priv->vfs_handle = NULL;
+ g_free (view->priv->vfs_read_buffer);
+ view->priv->vfs_read_buffer = NULL;
+}
+
+
+/* this takes a "nautilus" uri, not a "mozilla" uri and uses (sometimes) GnomeVFS */
+static void
+navigate_mozilla_to_nautilus_uri (EphyNautilusView *view,
+ const char *uri)
+{
+ char *old_uri;
+
+ cancel_pending_vfs_operation (view);
+
+ if (!GTK_WIDGET_REALIZED (view->priv->embed->mozembed)) {
+
+ /* Doing certain things to gtkmozembed before
+ * the widget has realized (specifically, opening
+ * content streams) can cause crashes. To avoid
+ * this, we postpone all navigations
+ * until the widget has realized (we believe
+ * premature realization may cause other issues)
+ */
+
+ DEBUG_MSG (("=%s: Postponing navigation request to widget realization\n", G_GNUC_FUNCTION));
+ /* Note that view->priv->uri is still set below */
+ } else {
+ if (should_mozilla_load_uri_directly (uri)) {
+
+ /* See if the current URI is the same as what mozilla already
+ * has. If so, issue a reload rather than a load.
+ * We ask mozilla for it's uri rather than using view->priv->uri because,
+ * from time to time, our understanding of mozilla's URI can become inaccurate
+ * (in particular, certain errors may cause embedded mozilla to not change
+ * locations)
+ */
+
+ old_uri = view->priv->embed->location;
+
+ if (old_uri != NULL && uris_identical (uri, old_uri)) {
+ DEBUG_MSG (("=%s uri's identical, telling ephy to reload\n", G_GNUC_FUNCTION));
+ embed_reload (view->priv->embed,
+ GTK_MOZ_EMBED_FLAG_RELOADBYPASSCACHE);
+ } else {
+ embed_load_url (view->priv->embed, uri);
+ }
+
+ } else {
+ DEBUG_MSG (("=%s loading URI via gnome-vfs\n", G_GNUC_FUNCTION));
+ gnome_vfs_async_open (&(view->priv->vfs_handle), uri,
+ GNOME_VFS_OPEN_READ, GNOME_VFS_PRIORITY_DEFAULT,
+ vfs_open_cb, view);
+ }
+ }
+
+ g_free (view->priv->uri);
+ view->priv->uri = g_strdup (uri);
+
+ DEBUG_MSG (("=%s current URI is now '%s'\n", G_GNUC_FUNCTION, view->priv->uri));
+}
+
+/*
+ * This a list of URI schemes that mozilla should load directly, rather than load through gnome-vfs
+ */
+static gboolean
+should_mozilla_load_uri_directly (const char *uri)
+{
+ static const char *handled_by_mozilla[] =
+ {
+ "http",
+ "file",
+ "toc",
+ "man",
+ "info",
+ "ghelp",
+ "gnome-help",
+ "https",
+ NULL
+ };
+ gint i;
+ gint uri_length;
+
+ if (uri == NULL) return FALSE;
+
+ uri_length = strlen (uri);
+
+ for (i = 0; handled_by_mozilla[i] != NULL; i++)
+ {
+ const gchar *current = handled_by_mozilla[i];
+ gint current_length = strlen (current);
+ if ((uri_length >= current_length)
+ && (!strncasecmp (uri, current, current_length)))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+#endif
diff --git a/src/ephy-nautilus-view.h b/src/ephy-nautilus-view.h
new file mode 100644
index 000000000..3dd13560b
--- /dev/null
+++ b/src/ephy-nautilus-view.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2001, 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef EPHY_NAUTILUS_VIEW_H
+#define EPHY_NAUTILUS_VIEW_H
+
+#include <libnautilus/nautilus-view.h>
+#include "ephy-shell.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NAUTILUS_VIEW (ephy_nautilus_view_get_type ())
+#define EPHY_NAUTILUS_VIEW(obj) (GTK_CHECK_CAST ((obj), EPHY_TYPE_NAUTILUS_VIEW, \
+ EphyNautilusView))
+#define EPHY_NAUTILUS_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TYPE_NAUTILUS_VIEW, \
+ EphyNautilusViewClass))
+#define EPHY_IS_NAUTILUS_VIEW(obj) (GTK_CHECK_TYPE ((obj), EPHY_TYPE_NAUTILUS_VIEW))
+#define EPHY_IS_NAUTILUS_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_IS_NAUTILUS_VIEW_CLASS))
+
+typedef struct EphyNautilusView EphyNautilusView;
+typedef struct EphyNautilusViewClass EphyNautilusViewClass;
+typedef struct EphyNautilusViewPrivate EphyNautilusViewPrivate;
+
+struct EphyNautilusView
+{
+ NautilusView parent;
+ EphyNautilusViewPrivate *priv;
+};
+
+struct EphyNautilusViewClass
+{
+ NautilusViewClass parent_class;
+};
+
+
+GType ephy_nautilus_view_get_type (void);
+BonoboObject * ephy_nautilus_view_new_component (EphyShell *gs);
+
+/* old public methods, probably all of them are going to be killed */
+
+void
+ephy_nautilus_view_set_title (EphyNautilusView *view,
+ const gchar *title);
+void
+ephy_nautilus_view_set_location (EphyNautilusView *view,
+ const gchar *uri);
+void
+ephy_nautilus_view_set_statusbar (EphyNautilusView *view,
+ const gchar *message);
+void
+ephy_nautilus_view_report_load_underway (EphyNautilusView *view);
+
+void
+ephy_nautilus_view_report_load_complete (EphyNautilusView *view);
+
+void
+ephy_nautilus_view_report_load_progress (EphyNautilusView *view,
+ double value);
+void
+ephy_nautilus_view_report_zoom (EphyNautilusView *view,
+ gint level);
+
+void ephy_nautilus_view_open_in_new_window (EphyNautilusView *view,
+ const gchar *url);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
new file mode 100644
index 000000000..eeacdf819
--- /dev/null
+++ b/src/ephy-shell.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-shell.h"
+#include "ephy-embed-shell.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-favicon-cache.h"
+#include "ephy-stock-icons.h"
+#include "ephy-filesystem-autocompletion.h"
+#include "ephy-window.h"
+#include "ephy-file-helpers.h"
+#include "ephy-thread-helpers.h"
+
+#include <libgnomeui/gnome-client.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-i18n.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkmessagedialog.h>
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+#include <bonobo/bonobo-generic-factory.h>
+#include "ephy-nautilus-view.h"
+
+#define EPHY_NAUTILUS_VIEW_OAFIID "OAFIID:GNOME_Ephy_NautilusViewFactory"
+
+#endif
+
+struct EphyShellPrivate
+{
+ EphyEmbedShell *embed_shell;
+ Session *session;
+ EphyAutocompletion *autocompletion;
+ EphyBookmarks *bookmarks;
+};
+
+enum
+{
+ STARTPAGE_HOME,
+ STARTPAGE_LAST,
+ STARTPAGE_BLANK,
+};
+
+static void
+ephy_shell_class_init (EphyShellClass *klass);
+static void
+ephy_shell_init (EphyShell *gs);
+static void
+ephy_shell_finalize (GObject *object);
+static void
+ephy_init_services (EphyShell *gs);
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+static void
+ephy_nautilus_view_init_factory (EphyShell *gs);
+static BonoboObject *
+ephy_nautilus_view_new (BonoboGenericFactory *factory,
+ const char *id,
+ EphyShell *gs);
+
+#endif
+
+static GObjectClass *parent_class = NULL;
+
+EphyShell *ephy_shell;
+
+GType
+ephy_shell_get_type (void)
+{
+ static GType ephy_shell_type = 0;
+
+ if (ephy_shell_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyShellClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_shell_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyShell),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_shell_init
+ };
+
+ ephy_shell_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyShell",
+ &our_info, 0);
+ }
+
+ return ephy_shell_type;
+
+}
+
+static void
+ephy_shell_class_init (EphyShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_shell_finalize;
+}
+
+static void
+ephy_shell_new_window_cb (EphyEmbedShell *shell,
+ EphyEmbed **new_embed,
+ EmbedChromeMask chromemask,
+ gpointer data)
+{
+ EphyTab *new_tab;
+ EphyWindow *window;
+ gboolean open_in_tab;
+
+ g_assert (new_embed != NULL);
+
+ open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ?
+ FALSE :
+ eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS);
+
+ if (open_in_tab)
+ {
+ window = ephy_shell_get_active_window (ephy_shell);
+ }
+ else
+ {
+ window = ephy_window_new ();
+ ephy_window_set_chrome (window, chromemask);
+ }
+
+ new_tab = ephy_tab_new ();
+ ephy_window_add_tab (window, new_tab, FALSE);
+ *new_embed = ephy_tab_get_embed (new_tab);
+}
+
+static void
+ephy_shell_init (EphyShell *gs)
+{
+ ephy_shell = gs;
+ g_object_add_weak_pointer (G_OBJECT(ephy_shell),
+ (gpointer *)&ephy_shell);
+
+ ephy_thread_helpers_init ();
+ ephy_node_system_init ();
+ ephy_file_helpers_init ();
+ ephy_stock_icons_init ();
+ ephy_ensure_dir_exists (ephy_dot_dir ());
+
+ gs->priv = g_new0 (EphyShellPrivate, 1);
+ gs->priv->session = NULL;
+ gs->priv->bookmarks = NULL;
+
+ gs->priv->embed_shell = ephy_embed_shell_new ("mozilla");
+
+ g_assert (gs->priv->embed_shell != NULL);
+
+ g_signal_connect (G_OBJECT(embed_shell),
+ "new_window_orphan",
+ G_CALLBACK(ephy_shell_new_window_cb),
+ NULL);
+
+ ephy_init_services (gs);
+}
+
+static void
+ephy_shell_finalize (GObject *object)
+{
+ EphyShell *gs;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_SHELL (object));
+
+ gs = EPHY_SHELL (object);
+
+ g_return_if_fail (gs->priv != NULL);
+
+ g_assert (ephy_shell == NULL);
+
+ g_return_if_fail (IS_EPHY_EMBED_SHELL (gs->priv->embed_shell));
+ g_object_unref (G_OBJECT (gs->priv->embed_shell));
+
+ if (gs->priv->session)
+ {
+ g_return_if_fail (IS_SESSION(gs->priv->session));
+ g_object_remove_weak_pointer
+ (G_OBJECT(gs->priv->session),
+ (gpointer *)&gs->priv->session);
+ g_object_unref (G_OBJECT (gs->priv->session));
+ }
+
+ if (gs->priv->autocompletion)
+ {
+ g_object_unref (gs->priv->autocompletion);
+ }
+
+ if (gs->priv->bookmarks)
+ {
+ g_object_unref (gs->priv->bookmarks);
+ }
+
+ ephy_file_helpers_shutdown ();
+ ephy_node_system_shutdown ();
+
+ g_free (gs->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("Ephy shell finalized\n");
+#endif
+
+ bonobo_main_quit ();
+
+#ifdef DEBUG_MARCO
+ g_print ("Bonobo quit done\n");
+#endif
+}
+
+EphyShell *
+ephy_shell_new (void)
+{
+ return EPHY_SHELL (g_object_new (EPHY_SHELL_TYPE, NULL));
+}
+
+/**
+ * ephy_shell_get_embed_shell:
+ * @gs: a #EphyShell
+ *
+ * Returns the embed shell created by the #EphyShell
+ *
+ * Return value: the embed shell
+ **/
+EphyEmbedShell *
+ephy_shell_get_embed_shell (EphyShell *gs)
+{
+ g_return_val_if_fail (IS_EPHY_SHELL (gs), NULL);
+
+ return gs->priv->embed_shell;
+}
+
+static void
+ephy_init_services (EphyShell *gs)
+{
+ /* preload the prefs */
+ /* it also enables notifiers support */
+ eel_gconf_monitor_add ("/apps/epiphany");
+ eel_gconf_monitor_add ("/apps/nautilus/preferences");
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+ ephy_nautilus_view_init_factory (gs);
+
+#endif
+
+}
+
+static char *
+build_homepage_url (EphyShell *gs,
+ EphyEmbed *previous_embed)
+{
+ const gchar *last_page_url;
+ gchar *home_page_url;
+ gint page_type;
+ EphyHistory *gh;
+ char *result = NULL;
+
+ if (previous_embed == NULL)
+ {
+ page_type = STARTPAGE_HOME;
+ }
+ else
+ {
+ page_type = eel_gconf_get_integer (CONF_GENERAL_NEWPAGE_TYPE);
+ }
+
+ /* return the appropriate page */
+ if (page_type == STARTPAGE_HOME)
+ {
+ /* get location of home page */
+ home_page_url = eel_gconf_get_string(CONF_GENERAL_HOMEPAGE);
+ result = home_page_url;
+ }
+ else if (page_type == STARTPAGE_LAST)
+ {
+ if (previous_embed != NULL)
+ {
+ ephy_embed_get_location (previous_embed,
+ TRUE, TRUE,
+ &result);
+ }
+
+ if (result == NULL)
+ {
+ /* get location of last page */
+ gh = ephy_embed_shell_get_global_history
+ (gs->priv->embed_shell);
+ last_page_url = ephy_history_get_last_page (gh);
+ result = g_strdup (last_page_url);
+ }
+ }
+
+ if (result == NULL)
+ {
+ /* even in case of error, it's a good default */
+ result = g_strdup ("about:blank");
+ }
+
+ return result;
+}
+
+/**
+ * ephy_shell_get_active_window:
+ * @gs: a #EphyShell
+ *
+ * Get the current active window. Use it when you
+ * need to take an action (like opening an url) on
+ * a window but you dont have a target window.
+ * Ex. open a new tab from command line.
+ *
+ * Return value: the current active window
+ **/
+EphyWindow *
+ephy_shell_get_active_window (EphyShell *gs)
+{
+ Session *session;
+ GList *windows;
+
+ session = ephy_shell_get_session (gs);
+ windows = session_get_windows (session);
+
+ if (windows == NULL) return NULL;
+
+ return EPHY_WINDOW(windows->data);
+}
+
+/**
+ * ephy_shell_new_tab:
+ * @shell: a #EphyShell
+ * @parent_window: the target #EphyWindow or %NULL
+ * @previous_tab: the referrer tab or %NULL
+ * @url: an url to load or %NULL
+ *
+ * Create a new tab and the parent window when necessary.
+ * Ever use this function to open urls in new window/tabs.
+ *
+ * ReturnValue: the created #EphyTab
+ **/
+EphyTab *
+ephy_shell_new_tab (EphyShell *shell,
+ EphyWindow *parent_window,
+ EphyTab *previous_tab,
+ const char *url,
+ EphyNewTabFlags flags)
+{
+ EphyWindow *window;
+ EphyTab *tab;
+ EphyEmbed *embed;
+ gboolean in_new_window;
+ gboolean jump_to;
+ EphyEmbed *previous_embed = NULL;
+
+ in_new_window = !eel_gconf_get_boolean (CONF_TABS_TABBED);
+
+ if (flags & EPHY_NEW_TAB_IN_NEW_WINDOW) in_new_window = TRUE;
+ if (flags & EPHY_NEW_TAB_IN_EXISTING_WINDOW) in_new_window = FALSE;
+
+ jump_to = eel_gconf_get_boolean (CONF_TABS_TABBED_AUTOJUMP);
+
+ if (flags & EPHY_NEW_TAB_JUMP) jump_to = TRUE;
+ if (flags & EPHY_NEW_TAB_DONT_JUMP_TO) jump_to = FALSE;
+
+ if (!in_new_window && parent_window != NULL)
+ {
+ window = parent_window;
+ }
+ else
+ {
+ window = ephy_window_new ();
+ }
+
+ if (previous_tab)
+ {
+ previous_embed = ephy_tab_get_embed (previous_tab);
+ }
+
+ tab = ephy_tab_new ();
+ embed = ephy_tab_get_embed (tab);
+ gtk_widget_show (GTK_WIDGET(embed));
+ ephy_window_add_tab (window, tab,
+ jump_to);
+ gtk_widget_show (GTK_WIDGET(window));
+
+ if (flags & EPHY_NEW_TAB_HOMEPAGE)
+ {
+ char *homepage;
+
+ homepage = build_homepage_url (shell, previous_embed);
+ g_assert (homepage != NULL);
+
+ ephy_embed_load_url (embed, homepage);
+
+ g_free (homepage);
+ }
+ else if ((flags & EPHY_NEW_TAB_IS_A_COPY) ||
+ (flags & EPHY_NEW_TAB_VIEW_SOURCE))
+ {
+ EmbedDisplayType display_type =
+ (flags & EPHY_NEW_TAB_VIEW_SOURCE) ?
+ DISPLAY_AS_SOURCE : DISPLAY_NORMAL;
+ EphyEmbed *source = ephy_tab_get_embed(previous_tab);
+ ephy_embed_load_url (embed, "about:blank");
+ ephy_embed_copy_page (embed, source, display_type);
+ }
+ else if (url)
+ {
+ ephy_embed_load_url (embed, url);
+ }
+
+ return tab;
+}
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+static void
+ephy_nautilus_view_init_factory (EphyShell *gs)
+{
+ BonoboGenericFactory *ephy_nautilusview_factory;
+ ephy_nautilusview_factory = bonobo_generic_factory_new
+ (EPHY_NAUTILUS_VIEW_OAFIID,
+ (BonoboFactoryCallback) ephy_nautilus_view_new, gs);
+ if (!BONOBO_IS_GENERIC_FACTORY (ephy_nautilusview_factory))
+ g_warning ("Couldn't create the factory!");
+
+}
+
+static BonoboObject *
+ephy_nautilus_view_new (BonoboGenericFactory *factory, const char *id,
+ EphyShell *gs)
+{
+ return ephy_nautilus_view_new_component (gs);
+}
+
+#endif
+
+/**
+ * ephy_shell_get_session:
+ * @gs: a #EphyShell
+ *
+ * Returns current session.
+ *
+ * Return value: the current session.
+ **/
+Session *
+ephy_shell_get_session (EphyShell *gs)
+{
+ if (!gs->priv->session)
+ {
+ gs->priv->session = session_new ();
+ g_object_add_weak_pointer
+ (G_OBJECT(gs->priv->session),
+ (gpointer *)&gs->priv->session);
+ }
+
+ return gs->priv->session;
+}
+
+EphyAutocompletion *
+ephy_shell_get_autocompletion (EphyShell *gs)
+{
+ EphyShellPrivate *p = gs->priv;
+
+ if (!p->autocompletion)
+ {
+ static const gchar *prefixes[] = {
+ EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES,
+ NULL
+ };
+
+ EphyHistory *gh = ephy_embed_shell_get_global_history (gs->priv->embed_shell);
+ EphyFilesystemAutocompletion *fa = ephy_filesystem_autocompletion_new ();
+ p->autocompletion = ephy_autocompletion_new ();
+ ephy_autocompletion_set_prefixes (p->autocompletion, prefixes);
+
+ ephy_autocompletion_add_source (p->autocompletion,
+ EPHY_AUTOCOMPLETION_SOURCE (gh));
+ ephy_autocompletion_add_source (p->autocompletion,
+ EPHY_AUTOCOMPLETION_SOURCE (fa));
+ ephy_autocompletion_add_source (p->autocompletion,
+ EPHY_AUTOCOMPLETION_SOURCE (gs->priv->bookmarks));
+
+ g_object_unref (fa);
+ g_object_unref (gs->priv->bookmarks);
+ }
+ return p->autocompletion;
+}
+
+EphyBookmarks *
+ephy_shell_get_bookmarks (EphyShell *gs)
+{
+ if (gs->priv->bookmarks == NULL)
+ {
+ gs->priv->bookmarks = ephy_bookmarks_new ();
+ }
+
+ return gs->priv->bookmarks;
+}
diff --git a/src/ephy-shell.h b/src/ephy-shell.h
new file mode 100644
index 000000000..3590931f9
--- /dev/null
+++ b/src/ephy-shell.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_SHELL_H
+#define EPHY_SHELL_H
+
+#include "ephy-autocompletion.h"
+#include "prefs-dialog.h"
+#include "downloader-view.h"
+#include "ephy-embed-shell.h"
+#include "session.h"
+#include "ephy-bookmarks.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#ifndef EPHY_SHELL_TYPE_DEF
+typedef struct EphyShell EphyShell;
+#define EPHY_SHELL_TYPE_DEF
+#endif
+
+typedef struct EphyShellClass EphyShellClass;
+
+#define EPHY_SHELL_TYPE (ephy_shell_get_type ())
+#define EPHY_SHELL(obj) (GTK_CHECK_CAST ((obj), EPHY_SHELL_TYPE, EphyShell))
+#define EPHY_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_SHELL, EphyShellClass))
+#define IS_EPHY_SHELL(obj) (GTK_CHECK_TYPE ((obj), EPHY_SHELL_TYPE))
+#define IS_EPHY_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_SHELL))
+
+typedef struct EphyShellPrivate EphyShellPrivate;
+
+extern EphyShell *ephy_shell;
+
+typedef enum
+{
+ EPHY_NEW_TAB_HOMEPAGE = 1 << 0,
+ EPHY_NEW_TAB_FULLSCREEN = 1 << 1,
+ EPHY_NEW_TAB_APPEND = 1 << 2,
+ EPHY_NEW_TAB_PREPEND = 1 << 3,
+ EPHY_NEW_TAB_APPEND_AFTER_CURRENT = 1 << 4,
+ EPHY_NEW_TAB_JUMP = 1 << 5,
+ EPHY_NEW_TAB_DONT_JUMP_TO = 1 << 6,
+ EPHY_NEW_TAB_RAISE_WINDOW = 1 << 7,
+ EPHY_NEW_TAB_DONT_RAISE_WINDOW = 1 << 8,
+ EPHY_NEW_TAB_IN_NEW_WINDOW = 1 << 9,
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW = 1 << 10,
+ EPHY_NEW_TAB_IS_A_COPY = 1 << 11,
+ EPHY_NEW_TAB_VIEW_SOURCE = 1 << 12
+} EphyNewTabFlags;
+
+struct EphyShell
+{
+ GObject parent;
+ EphyShellPrivate *priv;
+};
+
+struct EphyShellClass
+{
+ GObjectClass parent_class;
+};
+
+GType ephy_shell_get_type (void);
+
+EphyShell *ephy_shell_new (void);
+
+EphyEmbedShell *ephy_shell_get_embed_shell (EphyShell *gs);
+
+EphyWindow *ephy_shell_get_active_window (EphyShell *gs);
+
+EphyTab *ephy_shell_new_tab (EphyShell *shell,
+ EphyWindow *parent_window,
+ EphyTab *previous_tab,
+ const char *url,
+ EphyNewTabFlags flags);
+
+Session *ephy_shell_get_session (EphyShell *gs);
+
+EphyAutocompletion *ephy_shell_get_autocompletion (EphyShell *gs);
+
+EphyBookmarks *ephy_shell_get_bookmarks (EphyShell *gs);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-tab.c b/src/ephy-tab.c
new file mode 100644
index 000000000..b1fe71fb6
--- /dev/null
+++ b/src/ephy-tab.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define DEBUG_MSG(x) g_print x
+//#define DEBUG_MSG(x)
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+#include "ephy-tab.h"
+#include "ephy-shell.h"
+#include "ephy-embed-popup-bw.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+
+#include <bonobo/bonobo-i18n.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkmisc.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkiconfactory.h>
+#include <gtk/gtkstyle.h>
+#include <gtk/gtkselection.h>
+#include <string.h>
+
+struct EphyTabPrivate
+{
+ EphyEmbed *embed;
+ EphyWindow *window;
+ gboolean is_active;
+ TabLoadStatus load_status;
+ char status_message[255];
+ char *title;
+ char *location;
+ int load_percent;
+ gboolean visibility;
+ int cur_requests;
+ int total_requests;
+ int width;
+ int height;
+};
+
+static void
+ephy_tab_class_init (EphyTabClass *klass);
+static void
+ephy_tab_init (EphyTab *tab);
+static void
+ephy_tab_finalize (GObject *object);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_SHELL
+};
+
+static void
+ephy_tab_link_message_cb (EphyEmbed *embed,
+ const char *message,
+ EphyTab *tab);
+static void
+ephy_tab_js_status_cb (EphyEmbed *embed,
+ const char *status,
+ EphyTab *tab);
+static void
+ephy_tab_location_cb (EphyEmbed *embed, EphyTab *tab);
+static void
+ephy_tab_title_cb (EphyEmbed *embed, EphyTab *tab);
+static void
+ephy_tab_net_state_cb (EphyEmbed *embed, const char *uri,
+ EmbedState state, EphyTab *tab);
+static void
+ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
+ EmbedChromeMask chromemask, EphyTab *tab);
+static void
+ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility,
+ EphyTab *tab);
+static void
+ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab);
+static gint
+ephy_tab_open_uri_cb (EphyEmbed *embed, const char *uri,
+ EphyTab *tab);
+static void
+ephy_tab_size_to_cb (EphyEmbed *embed, gint width, gint height,
+ EphyTab *tab);
+static gint
+ephy_tab_dom_mouse_click_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab);
+static gint
+ephy_tab_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab);
+static void
+ephy_tab_security_change_cb (EphyEmbed *embed, EmbedSecurityLevel level,
+ EphyTab *tab);
+static void
+ephy_tab_zoom_changed_cb (EphyEmbed *embed, gint zoom,
+ EphyTab *tab);
+
+static GObjectClass *parent_class = NULL;
+
+/* Class functions */
+
+GType
+ephy_tab_get_type (void)
+{
+ static GType ephy_tab_type = 0;
+
+ if (ephy_tab_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyTabClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_tab_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyTab),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_tab_init
+ };
+
+ ephy_tab_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyTab",
+ &our_info, 0);
+ }
+
+ return ephy_tab_type;
+}
+
+static void
+ephy_tab_class_init (EphyTabClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_tab_finalize;
+}
+
+static void
+ephy_tab_parent_set_cb (GtkWidget *widget, GtkWidget *previous_parent,
+ EphyTab *tab)
+{
+ GtkWidget *toplevel;
+
+ /* FIXME maybe we dont need to set the tab parent explicitly
+ * anymore with this callback taking care of it */
+
+ if (widget->parent == NULL) return;
+
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ tab->priv->window = EPHY_WINDOW (toplevel);
+}
+
+static void
+ephy_tab_embed_destroy_cb (GtkWidget *widget, EphyTab *tab)
+{
+#ifdef DEBUG_MARCO
+ g_print ("GtkMozEmbed destroy signal on EphyTab\n");
+#endif
+ g_object_unref (tab);
+}
+
+static void
+ephy_tab_init (EphyTab *tab)
+{
+ GObject *embed, *embed_widget;
+ EphyEmbedShell *shell;
+
+ tab->priv = g_new0 (EphyTabPrivate, 1);
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+
+ tab->priv->embed = ephy_embed_new (G_OBJECT(shell));
+
+ tab->priv->window = NULL;
+ tab->priv->is_active = FALSE;
+ *tab->priv->status_message = '\0';
+ tab->priv->load_status = TAB_LOAD_NONE;
+ tab->priv->load_percent = 0;
+ tab->priv->title = NULL;
+ tab->priv->location = NULL;
+ tab->priv->total_requests = 0;
+ tab->priv->cur_requests = 0;
+ tab->priv->width = -1;
+ tab->priv->height = -1;
+
+
+ embed = G_OBJECT (tab->priv->embed);
+ embed_widget = G_OBJECT (tab->priv->embed);
+
+ /* set a pointer in the embed's widget back to the tab */
+ g_object_set_data (embed_widget, "EphyTab", tab);
+
+ g_signal_connect (embed_widget, "parent_set",
+ G_CALLBACK (ephy_tab_parent_set_cb),
+ tab);
+ g_signal_connect (embed_widget, "destroy",
+ GTK_SIGNAL_FUNC (ephy_tab_embed_destroy_cb),
+ tab);
+ g_signal_connect (embed, "ge_link_message",
+ GTK_SIGNAL_FUNC (ephy_tab_link_message_cb),
+ tab);
+ g_signal_connect (embed, "ge_js_status",
+ GTK_SIGNAL_FUNC (ephy_tab_js_status_cb),
+ tab);
+ g_signal_connect (embed, "ge_location",
+ GTK_SIGNAL_FUNC (ephy_tab_location_cb),
+ tab);
+ g_signal_connect (embed, "ge_title",
+ GTK_SIGNAL_FUNC (ephy_tab_title_cb),
+ tab);
+ g_signal_connect (embed, "ge_zoom_change",
+ GTK_SIGNAL_FUNC (ephy_tab_zoom_changed_cb),
+ tab);
+ g_signal_connect (embed, "ge_net_state",
+ GTK_SIGNAL_FUNC (ephy_tab_net_state_cb),
+ tab);
+ g_signal_connect (embed, "ge_new_window",
+ GTK_SIGNAL_FUNC (ephy_tab_new_window_cb),
+ tab);
+ g_signal_connect (embed, "ge_visibility",
+ GTK_SIGNAL_FUNC (ephy_tab_visibility_cb),
+ tab);
+ g_signal_connect (embed, "ge_destroy_brsr",
+ GTK_SIGNAL_FUNC (ephy_tab_destroy_brsr_cb),
+ tab);
+ g_signal_connect (embed, "ge_open_uri",
+ GTK_SIGNAL_FUNC (ephy_tab_open_uri_cb),
+ tab);
+ g_signal_connect (embed, "ge_size_to",
+ GTK_SIGNAL_FUNC (ephy_tab_size_to_cb),
+ tab);
+ g_signal_connect (embed, "ge_dom_mouse_click",
+ GTK_SIGNAL_FUNC (ephy_tab_dom_mouse_click_cb),
+ tab);
+ g_signal_connect (embed, "ge_dom_mouse_down",
+ GTK_SIGNAL_FUNC (ephy_tab_dom_mouse_down_cb),
+ tab);
+ g_signal_connect (embed, "ge_security_change",
+ GTK_SIGNAL_FUNC (ephy_tab_security_change_cb),
+ tab);
+}
+
+/* Destructor */
+
+static void
+ephy_tab_finalize (GObject *object)
+{
+ EphyTab *tab;
+
+ g_return_if_fail (IS_EPHY_TAB (object));
+
+ tab = EPHY_TAB (object);
+
+ g_return_if_fail (tab->priv != NULL);
+
+ g_idle_remove_by_data (tab->priv->embed);
+
+ g_free (tab->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("EphyTab finalized %p\n", tab);
+#endif
+}
+
+/* Public functions */
+
+EphyTab *
+ephy_tab_new ()
+{
+ EphyTab *tab;
+
+ tab = EPHY_TAB (g_object_new (EPHY_TAB_TYPE, NULL));
+ g_return_val_if_fail (tab->priv != NULL, NULL);
+ return tab;
+}
+
+static void
+ephy_tab_set_load_status (EphyTab *tab,
+ TabLoadStatus status)
+{
+ if (status == TAB_LOAD_COMPLETED)
+ {
+ Session *s;
+ s = ephy_shell_get_session (ephy_shell);
+ session_save (s, SESSION_CRASHED);
+ }
+
+ if (ephy_tab_get_is_active (tab) &&
+ status == TAB_LOAD_COMPLETED)
+ {
+ tab->priv->load_status = TAB_LOAD_NONE;
+ }
+ else
+ {
+ tab->priv->load_status = status;
+ }
+}
+
+EphyEmbed *
+ephy_tab_get_embed (EphyTab *tab)
+{
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ return tab->priv->embed;
+}
+
+void
+ephy_tab_set_window (EphyTab *tab, EphyWindow *window)
+{
+ g_return_if_fail (IS_EPHY_TAB (G_OBJECT (tab)));
+ if (window) g_return_if_fail (IS_EPHY_WINDOW (G_OBJECT (window)));
+
+ tab->priv->window = window;
+}
+
+EphyWindow *
+ephy_tab_get_window (EphyTab *tab)
+{
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ return tab->priv->window;
+}
+
+static void
+ephy_tab_update_color (EphyTab *tab)
+{
+ TabLoadStatus status = ephy_tab_get_load_status (tab);
+ EphyNotebookPageLoadStatus page_status = 0;
+ GtkWidget *nb;
+
+ nb = ephy_window_get_notebook (tab->priv->window);
+
+ switch (status)
+ {
+ case TAB_LOAD_NONE:
+ page_status = EPHY_NOTEBOOK_TAB_LOAD_NORMAL;
+ break;
+ case TAB_LOAD_STARTED:
+ page_status = EPHY_NOTEBOOK_TAB_LOAD_LOADING;
+ break;
+ case TAB_LOAD_COMPLETED:
+ page_status = EPHY_NOTEBOOK_TAB_LOAD_COMPLETED;
+ break;
+ }
+
+ ephy_notebook_set_page_status (EPHY_NOTEBOOK (nb),
+ GTK_WIDGET (tab->priv->embed),
+ page_status);
+}
+
+void
+ephy_tab_set_is_active (EphyTab *tab, gboolean is_active)
+{
+ TabLoadStatus status;
+
+ g_return_if_fail (IS_EPHY_TAB (G_OBJECT (tab)));
+
+ tab->priv->is_active = is_active;
+
+ status = ephy_tab_get_load_status (tab);
+ if (status == TAB_LOAD_COMPLETED)
+ {
+ ephy_tab_set_load_status (tab, TAB_LOAD_NONE);
+ }
+ ephy_tab_update_color (tab);
+}
+
+gboolean
+ephy_tab_get_is_active (EphyTab *tab)
+{
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), FALSE);
+
+ return tab->priv->is_active;
+}
+
+gboolean
+ephy_tab_get_visibility (EphyTab *tab)
+{
+ return tab->priv->visibility;
+}
+
+void
+ephy_tab_get_size (EphyTab *tab, int *width, int *height)
+{
+ *width = tab->priv->width;
+ *height = tab->priv->height;
+}
+
+static void
+ephy_tab_set_visibility (EphyTab *tab,
+ gboolean visible)
+{
+ g_return_if_fail (tab->priv->window != NULL);
+
+ /* FIXME show/hide the tab widget */
+
+ tab->priv->visibility = visible;
+}
+
+/* Private callbacks for embed signals */
+
+static void
+ephy_tab_link_message_cb (EphyEmbed *embed,
+ const char *message,
+ EphyTab *tab)
+{
+ if (!tab->priv->is_active) return;
+
+ g_strlcpy (tab->priv->status_message,
+ message, 255);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarMessageControl);
+}
+
+static void
+ephy_tab_js_status_cb (EphyEmbed *embed,
+ const char *status,
+ EphyTab *tab)
+{
+ if (!tab->priv->is_active)
+ return;
+
+ g_strlcpy (tab->priv->status_message,
+ status, 255);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarMessageControl);
+}
+
+static void
+ephy_tab_location_cb (EphyEmbed *embed, EphyTab *tab)
+{
+ if (tab->priv->location) g_free (tab->priv->location);
+ ephy_embed_get_location (embed, TRUE, FALSE,
+ &tab->priv->location);
+
+ if (tab->priv->is_active)
+ {
+ ephy_window_update_control (tab->priv->window, LocationControl);
+ ephy_window_update_control (tab->priv->window, NavControl);
+ }
+}
+
+static void
+ephy_tab_zoom_changed_cb (EphyEmbed *embed, gint zoom, EphyTab *tab)
+{
+ if (tab->priv->is_active)
+ {
+ ephy_window_update_control (tab->priv->window, ZoomControl);
+ }
+}
+
+static void
+ephy_tab_set_title (EphyTab *tab, const char *title)
+{
+ GtkWidget *nb;
+
+ nb = ephy_window_get_notebook (tab->priv->window);
+ ephy_notebook_set_page_title (EPHY_NOTEBOOK (nb),
+ GTK_WIDGET (tab->priv->embed),
+ title);
+}
+
+static void
+ephy_tab_title_cb (EphyEmbed *embed, EphyTab *tab)
+{
+ if (tab->priv->title) g_free (tab->priv->title);
+ ephy_embed_get_title (embed, &tab->priv->title);
+
+ if (*(tab->priv->title) == '\0')
+ {
+ g_free (tab->priv->title);
+ tab->priv->title = g_strdup (_("Untitled"));
+ }
+
+ ephy_tab_set_title (tab, tab->priv->title);
+
+ if (tab->priv->is_active)
+ {
+ ephy_window_update_control (tab->priv->window,
+ TitleControl);
+ }
+}
+
+static int
+build_load_percent (int bytes_loaded, int max_bytes_loaded)
+{
+ if (max_bytes_loaded > 0)
+ {
+ return (bytes_loaded * 100) / max_bytes_loaded;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static char *
+get_host_name_from_uri (const char *uri)
+{
+ GnomeVFSURI *vfs_uri = NULL;
+ const char *host = NULL;
+ char *result;
+
+ if (uri)
+ {
+ vfs_uri = gnome_vfs_uri_new (uri);
+ }
+
+ if (vfs_uri)
+ {
+ host = gnome_vfs_uri_get_host_name (vfs_uri);
+ }
+
+ if (!host)
+ {
+ host = _("site");
+ }
+
+ result = g_strdup (host);
+
+ if (vfs_uri) gnome_vfs_uri_unref (vfs_uri);
+
+ return result;
+}
+
+static void
+build_net_state_message (char *message,
+ const char *uri,
+ EmbedState flags)
+{
+ const char *msg = NULL;
+ char *host;
+
+ host = get_host_name_from_uri (uri);
+
+ /* IS_REQUEST and IS_NETWORK can be both set */
+
+ if (flags & EMBED_STATE_IS_REQUEST)
+ {
+ if (flags & EMBED_STATE_REDIRECTING)
+ {
+ msg = _("Redirecting to %s...");
+ }
+ else if (flags & EMBED_STATE_TRANSFERRING)
+ {
+ msg = _("Transferring data from %s...");
+ }
+ else if (flags & EMBED_STATE_NEGOTIATING)
+ {
+ msg = _("Waiting for authorization from %s...");
+ }
+ }
+
+ if (flags & EMBED_STATE_IS_NETWORK)
+ {
+ if (flags & EMBED_STATE_START)
+ {
+ msg = _("Loading %s...");
+ }
+ else if (flags & EMBED_STATE_STOP)
+ {
+ msg = _("Done.");
+ }
+ }
+
+ if (msg)
+ {
+ g_snprintf (message, 255, msg, host);
+ }
+
+ g_free (host);
+}
+
+static void
+build_progress_from_requests (EphyTab *tab, EmbedState state)
+{
+ int load_percent;
+
+ if (state & EMBED_STATE_IS_REQUEST)
+ {
+ if (state & EMBED_STATE_START)
+ {
+ tab->priv->total_requests ++;
+ }
+ else if (state & EMBED_STATE_STOP)
+ {
+ tab->priv->cur_requests ++;
+ }
+
+ load_percent = build_load_percent (tab->priv->cur_requests,
+ tab->priv->total_requests);
+ if (load_percent > tab->priv->load_percent)
+ {
+ tab->priv->load_percent = load_percent;
+ }
+ }
+}
+
+static void
+ensure_location (EphyTab *tab, const char *uri)
+{
+ if (tab->priv->location == NULL)
+ {
+ tab->priv->location = g_strdup (uri);
+ ephy_window_update_control (tab->priv->window,
+ LocationControl);
+ }
+}
+
+static void
+ephy_tab_net_state_cb (EphyEmbed *embed, const char *uri,
+ EmbedState state, EphyTab *tab)
+{
+ build_net_state_message (tab->priv->status_message, uri, state);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarMessageControl);
+
+ if (state & EMBED_STATE_IS_NETWORK)
+ {
+ if (state & EMBED_STATE_START)
+ {
+ tab->priv->total_requests = 0;
+ tab->priv->cur_requests = 0;
+ tab->priv->load_percent = 0;
+
+ ensure_location (tab, uri);
+
+ ephy_tab_set_load_status (tab, TAB_LOAD_STARTED);
+
+ ephy_window_update_control (tab->priv->window,
+ NavControl);
+ ephy_window_update_control (tab->priv->window,
+ SpinnerControl);
+ ephy_tab_update_color (tab);
+ }
+ else if (state & EMBED_STATE_STOP)
+ {
+ tab->priv->load_percent = 0;
+
+ ephy_tab_set_load_status (tab, TAB_LOAD_COMPLETED);
+
+ ephy_window_update_control (tab->priv->window,
+ NavControl);
+ ephy_window_update_control (tab->priv->window,
+ SpinnerControl);
+ ephy_tab_update_color (tab);
+ }
+ }
+
+ build_progress_from_requests (tab, state);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarProgressControl);
+}
+
+static void
+ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
+ EmbedChromeMask chromemask, EphyTab *tab)
+{
+ EphyTab *new_tab;
+ EphyWindow *window;
+ gboolean open_in_tab;
+
+ open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ?
+ FALSE :
+ eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS);
+
+ if (open_in_tab)
+ {
+ window = ephy_tab_get_window (tab);
+ }
+ else
+ {
+ window = ephy_window_new ();
+ ephy_window_set_chrome (window, chromemask);
+ }
+
+ new_tab = ephy_tab_new ();
+ ephy_window_add_tab (window, new_tab, FALSE);
+
+ *new_embed = ephy_tab_get_embed (new_tab);
+}
+
+static gboolean
+let_me_resize_hack (gpointer data)
+{
+ gtk_widget_set_size_request (GTK_WIDGET(data),
+ -1, -1);
+ return FALSE;
+}
+
+static void
+ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility,
+ EphyTab *tab)
+{
+ EphyWindow *window;
+
+ if (visibility)
+ {
+ gtk_widget_show (GTK_WIDGET(embed));
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET(embed));
+ }
+
+ ephy_tab_set_visibility (tab, visibility);
+
+ window = ephy_tab_get_window (tab);
+ g_return_if_fail (window != NULL);
+
+ ephy_window_update_control (window, WindowVisibilityControl);
+}
+
+static void
+ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab)
+{
+ EphyWindow *window;
+
+ window = ephy_tab_get_window (tab);
+
+ ephy_window_remove_tab (window, tab);
+}
+
+static gint
+ephy_tab_open_uri_cb (EphyEmbed *embed, const char *uri,
+ EphyTab *tab)
+{
+ return FALSE;
+}
+
+static void
+ephy_tab_size_to_cb (EphyEmbed *embed, gint width, gint height,
+ EphyTab *tab)
+{
+ GList *tabs;
+ EphyWindow *window;
+ GtkWidget *widget;
+ EmbedChromeMask chromemask;
+
+ tab->priv->width = width;
+ tab->priv->height = height;
+
+ window = ephy_tab_get_window (tab);
+ tabs = (GList *) ephy_window_get_tabs (window);
+ widget = GTK_WIDGET (embed);
+ chromemask = ephy_window_get_chrome (window);
+
+ /* Do not resize window with multiple tabs.
+ * Do not resize window already showed because
+ * it's not possible to calculate a sensible window
+ * size based on the embed size */
+ if (g_list_length (tabs) == 1 && !tab->priv->visibility)
+ {
+ gtk_widget_set_size_request
+ (widget, width, height);
+
+ /* HACK reset widget requisition after the container
+ * has been resized. It appears to be the only way
+ * to have the window sized according to embed
+ * size correctly.
+ * We dont do it for XUL dialogs because in that case
+ * a "forced" requisition appear correct.
+ */
+ if (!(chromemask & EMBED_CHROME_OPENASCHROME))
+ {
+ g_idle_add (let_me_resize_hack, embed);
+ }
+ }
+}
+
+static gint
+ephy_tab_dom_mouse_click_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab)
+{
+ return FALSE;
+}
+
+static void
+ephy_tab_show_embed_popup (EphyTab *tab, EphyEmbedEvent *event)
+{
+ EphyEmbedPopup *popup;
+ EphyWindow *window;
+ EphyEmbed *embed;
+
+ window = ephy_tab_get_window (tab);
+ embed = ephy_tab_get_embed (tab);
+
+ popup = EPHY_EMBED_POPUP (ephy_window_get_popup_factory (window));
+ ephy_embed_popup_set_event (popup, event);
+ ephy_embed_popup_show (popup, embed);
+}
+
+static gint
+ephy_tab_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab)
+{
+ EphyWindow *window;
+ int button;
+ EmbedEventContext context;
+
+ g_assert (IS_EPHY_EMBED_EVENT(event));
+
+ window = ephy_tab_get_window (tab);
+ g_return_val_if_fail (window != NULL, FALSE);
+
+ ephy_embed_event_get_mouse_button (event, &button);
+ ephy_embed_event_get_context (event, &context);
+
+ if (button == 2)
+ {
+ ephy_tab_show_embed_popup (tab, event);
+ }
+ else if (button == 1
+ && (context & EMBED_CONTEXT_LINK))
+ {
+ GValue *value;
+
+ ephy_embed_event_get_property (event, "link", &value);
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ g_value_get_string (value), 0);
+ }
+ else if (button == 1
+ && !(context & EMBED_CONTEXT_LINK
+ || context & EMBED_CONTEXT_EMAIL_LINK
+ || context & EMBED_CONTEXT_INPUT))
+ {
+ /* paste url */
+ gtk_selection_convert (GTK_WIDGET (window),
+ GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_STRING,
+ GDK_CURRENT_TIME);
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_tab_security_change_cb (EphyEmbed *embed, EmbedSecurityLevel level,
+ EphyTab *tab)
+{
+ if (!tab->priv->is_active) return;
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarSecurityControl);
+}
+
+TabLoadStatus
+ephy_tab_get_load_status (EphyTab *tab)
+{
+ return tab->priv->load_status;
+}
+
+int
+ephy_tab_get_load_percent (EphyTab *tab)
+{
+ return tab->priv->load_percent;
+}
+
+const char *
+ephy_tab_get_status_message (EphyTab *tab)
+{
+ if (tab->priv->status_message)
+ {
+ return tab->priv->status_message;
+ }
+ else
+ {
+ return " ";
+ }
+}
+
+const char *
+ephy_tab_get_title (EphyTab *tab)
+{
+ if (tab->priv->title &&
+ g_utf8_strlen(tab->priv->title, -1))
+ {
+ return tab->priv->title;
+ }
+ else
+ {
+ return _("Untitled");
+ }
+}
+
+const char *
+ephy_tab_get_location (EphyTab *tab)
+{
+ return tab->priv->location;
+}
+
+void
+ephy_tab_set_location (EphyTab *tab,
+ char *location)
+{
+ if (tab->priv->location) g_free (tab->priv->location);
+ tab->priv->location = location;
+}
+
+void
+ephy_tab_update_control (EphyTab *tab,
+ TabControlID id)
+{
+ switch (id)
+ {
+ case TAB_CONTROL_TITLE:
+ ephy_tab_set_title (tab, tab->priv->title);
+ break;
+ }
+}
diff --git a/src/ephy-tab.h b/src/ephy-tab.h
new file mode 100644
index 000000000..02e06746f
--- /dev/null
+++ b/src/ephy-tab.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TAB_H
+#define EPHY_TAB_H
+
+#include "ephy-embed.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyTabClass EphyTabClass;
+
+#define EPHY_TAB_TYPE (ephy_tab_get_type ())
+#define EPHY_TAB(obj) (GTK_CHECK_CAST ((obj), EPHY_TAB_TYPE, EphyTab))
+#define EPHY_TAB_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TAB, EphyTabClass))
+#define IS_EPHY_TAB(obj) (GTK_CHECK_TYPE ((obj), EPHY_TAB_TYPE))
+#define IS_EPHY_TAB_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_TAB))
+
+typedef struct EphyTab EphyTab;
+typedef struct EphyTabPrivate EphyTabPrivate;
+
+typedef enum
+{
+ TAB_CONTROL_TITLE
+} TabControlID;
+
+typedef enum
+{
+ TAB_LOAD_NONE,
+ TAB_LOAD_STARTED,
+ TAB_LOAD_COMPLETED
+} TabLoadStatus;
+
+struct EphyTab
+{
+ GObject parent;
+ EphyTabPrivate *priv;
+};
+
+struct EphyTabClass
+{
+ GObjectClass parent_class;
+};
+
+/* Include the header down here to resolve circular dependency */
+#include "ephy-window.h"
+
+GType ephy_tab_get_type (void);
+
+EphyTab *ephy_tab_new (void);
+
+EphyEmbed *ephy_tab_get_embed (EphyTab *tab);
+
+void ephy_tab_set_window (EphyTab *tab,
+ EphyWindow *window);
+
+EphyWindow *ephy_tab_get_window (EphyTab *tab);
+
+void ephy_tab_set_is_active (EphyTab *tab,
+ gboolean is_active);
+
+gboolean ephy_tab_get_is_active (EphyTab *tab);
+
+gboolean ephy_tab_get_visibility (EphyTab *tab);
+
+TabLoadStatus ephy_tab_get_load_status (EphyTab *tab);
+
+int ephy_tab_get_load_percent (EphyTab *tab);
+
+const char *ephy_tab_get_status_message (EphyTab *tab);
+
+const char *ephy_tab_get_title (EphyTab *tab);
+
+const char *ephy_tab_get_location (EphyTab *tab);
+
+void ephy_tab_set_location (EphyTab *tab,
+ char *location);
+
+void ephy_tab_get_size (EphyTab *tab,
+ int *width,
+ int *height);
+
+void ephy_tab_update_control (EphyTab *tab,
+ TabControlID id);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-window.c b/src/ephy-window.c
new file mode 100644
index 000000000..311d6202c
--- /dev/null
+++ b/src/ephy-window.c
@@ -0,0 +1,1428 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ephy-window.h"
+#include "ephy-favorites-menu.h"
+#include "ephy-state.h"
+#include "ephy-gobject-misc.h"
+#include "statusbar.h"
+#include "toolbar.h"
+#include "ppview-toolbar.h"
+#include "window-commands.h"
+#include "find-dialog.h"
+#include "history-dialog.h"
+#include "popup-commands.h"
+#include "ephy-shell.h"
+#include "ephy-bonobo-extensions.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-utils.h"
+
+#include <string.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-ui-util.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <gtk/gtk.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+
+#define CHARSET_MENU_PATH "/menu/View/EncodingMenuPlaceholder"
+#define GO_FAVORITES_PATH "/menu/Go/Favorites"
+
+#define GO_BACK_CMD_PATH "/commands/GoBack"
+#define GO_FORWARD_CMD_PATH "/commands/GoForward"
+#define GO_UP_CMD_PATH "/commands/GoUp"
+#define EDIT_FIND_NEXT_CMD_PATH "/commands/EditFindNext"
+#define EDIT_FIND_PREV_CMD_PATH "/commands/EditFindPrev"
+#define VIEW_MENUBAR_PATH "/commands/View Menubar"
+#define VIEW_STATUSBAR_PATH "/commands/View Statusbar"
+#define VIEW_TOOLBAR_PATH "/commands/View Toolbar"
+#define VIEW_BOOKMARKSBAR_PATH "/commands/View BookmarksBar"
+#define VIEW_FULLSCREEN_PATH "/commands/View Fullscreen"
+
+#define ID_VIEW_MENUBAR "View Menubar"
+#define ID_VIEW_STATUSBAR "View Statusbar"
+#define ID_VIEW_TOOLBAR "View Toolbar"
+#define ID_VIEW_BOOKMARKSBAR "View BookmarksBar"
+#define ID_VIEW_FULLSCREEN "View Fullscreen"
+
+static BonoboUIVerb ephy_verbs [] = {
+ BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn)window_cmd_edit_find),
+ BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn)window_cmd_file_print),
+ BONOBO_UI_VERB ("GoStop", (BonoboUIVerbFn)window_cmd_go_stop),
+ BONOBO_UI_VERB ("GoReload", (BonoboUIVerbFn)window_cmd_go_reload),
+ BONOBO_UI_VERB ("GoBack", (BonoboUIVerbFn)window_cmd_go_back),
+ BONOBO_UI_VERB ("GoForward", (BonoboUIVerbFn)window_cmd_go_forward),
+ BONOBO_UI_VERB ("GoGo", (BonoboUIVerbFn)window_cmd_go_go),
+ BONOBO_UI_VERB ("GoUp", (BonoboUIVerbFn)window_cmd_go_up),
+ BONOBO_UI_VERB ("GoHome", (BonoboUIVerbFn)window_cmd_go_home),
+ BONOBO_UI_VERB ("GoMyportal", (BonoboUIVerbFn)window_cmd_go_myportal),
+ BONOBO_UI_VERB ("GoLocation", (BonoboUIVerbFn)window_cmd_go_location),
+ BONOBO_UI_VERB ("FileNew", (BonoboUIVerbFn)window_cmd_new),
+ BONOBO_UI_VERB ("FileNewWindow", (BonoboUIVerbFn)window_cmd_new_window),
+ BONOBO_UI_VERB ("FileNewTab", (BonoboUIVerbFn)window_cmd_new_tab),
+ BONOBO_UI_VERB ("FileOpen", (BonoboUIVerbFn)window_cmd_file_open),
+ BONOBO_UI_VERB ("FileSaveAs", (BonoboUIVerbFn)window_cmd_file_save_as),
+ BONOBO_UI_VERB ("FileCloseTab", (BonoboUIVerbFn)window_cmd_file_close_tab),
+ BONOBO_UI_VERB ("FileCloseWindow", (BonoboUIVerbFn)window_cmd_file_close_window),
+ BONOBO_UI_VERB ("FileSendTo", (BonoboUIVerbFn)window_cmd_file_send_to),
+ BONOBO_UI_VERB ("EditCut", (BonoboUIVerbFn)window_cmd_edit_cut),
+ BONOBO_UI_VERB ("EditCopy", (BonoboUIVerbFn)window_cmd_edit_copy),
+ BONOBO_UI_VERB ("EditPaste", (BonoboUIVerbFn)window_cmd_edit_paste),
+ BONOBO_UI_VERB ("EditSelectAll", (BonoboUIVerbFn)window_cmd_edit_select_all),
+ BONOBO_UI_VERB ("EditPrefs", (BonoboUIVerbFn)window_cmd_edit_prefs),
+ BONOBO_UI_VERB ("SettingsToolbarEditor", (BonoboUIVerbFn)window_cmd_settings_toolbar_editor),
+ BONOBO_UI_VERB ("Zoom In", (BonoboUIVerbFn)window_cmd_view_zoom_in),
+ BONOBO_UI_VERB ("EditFindNext", (BonoboUIVerbFn)window_cmd_edit_find_next),
+ BONOBO_UI_VERB ("EditFindPrev", (BonoboUIVerbFn)window_cmd_edit_find_prev),
+ BONOBO_UI_VERB ("Zoom Out", (BonoboUIVerbFn)window_cmd_view_zoom_out),
+ BONOBO_UI_VERB ("Zoom Normal", (BonoboUIVerbFn)window_cmd_view_zoom_normal),
+ BONOBO_UI_VERB ("ViewPageSource", (BonoboUIVerbFn)window_cmd_view_page_source),
+ BONOBO_UI_VERB ("BookmarksAddDefault", (BonoboUIVerbFn)window_cmd_bookmarks_add_default),
+ BONOBO_UI_VERB ("BookmarksEdit", (BonoboUIVerbFn)window_cmd_bookmarks_edit),
+ BONOBO_UI_VERB ("ToolsHistory", (BonoboUIVerbFn)window_cmd_tools_history),
+ BONOBO_UI_VERB ("ToolsPDM", (BonoboUIVerbFn)window_cmd_tools_pdm),
+ BONOBO_UI_VERB ("TabsNext", (BonoboUIVerbFn)window_cmd_tabs_next),
+ BONOBO_UI_VERB ("TabsPrevious", (BonoboUIVerbFn)window_cmd_tabs_previous),
+ BONOBO_UI_VERB ("TabsMoveLeft", (BonoboUIVerbFn)window_cmd_tabs_move_left),
+ BONOBO_UI_VERB ("TabsMoveRight", (BonoboUIVerbFn)window_cmd_tabs_move_right),
+ BONOBO_UI_VERB ("TabsDetach", (BonoboUIVerbFn)window_cmd_tabs_detach),
+ BONOBO_UI_VERB ("HelpContents", (BonoboUIVerbFn)window_cmd_help_manual),
+ BONOBO_UI_VERB ("About", (BonoboUIVerbFn)window_cmd_help_about),
+
+ BONOBO_UI_VERB_END
+};
+
+static BonoboUIVerb ephy_popup_verbs [] = {
+ BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn)popup_cmd_new_window),
+ BONOBO_UI_VERB ("EPOpenInNewTab", (BonoboUIVerbFn)popup_cmd_new_tab),
+ BONOBO_UI_VERB ("EPAddBookmark", (BonoboUIVerbFn)popup_cmd_add_bookmark),
+ BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn)popup_cmd_image_in_new_window),
+ BONOBO_UI_VERB ("EPOpenImageInNewTab", (BonoboUIVerbFn)popup_cmd_image_in_new_tab),
+ BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn)popup_cmd_frame_in_new_window),
+ BONOBO_UI_VERB ("DPOpenFrameInNewTab", (BonoboUIVerbFn)popup_cmd_frame_in_new_tab),
+ BONOBO_UI_VERB ("DPAddFrameBookmark", (BonoboUIVerbFn)popup_cmd_add_frame_bookmark),
+ BONOBO_UI_VERB ("DPViewSource", (BonoboUIVerbFn)popup_cmd_view_source),
+
+ BONOBO_UI_VERB_END
+};
+
+struct EphyWindowPrivate
+{
+ EphyFavoritesMenu *fav_menu;
+ PPViewToolbar *ppview_toolbar;
+ Toolbar *toolbar;
+ Statusbar *statusbar;
+ GtkNotebook *notebook;
+ EphyTab *active_tab;
+ GtkWidget *sidebar;
+ EphyEmbedPopupBW *embed_popup;
+ EphyDialog *find_dialog;
+ EphyDialog *history_dialog;
+ EphyDialog *history_sidebar;
+ EmbedChromeMask chrome_mask;
+ gboolean ignore_layout_toggles;
+ gboolean has_default_size;
+ gboolean closing;
+};
+
+static void
+ephy_window_class_init (EphyWindowClass *klass);
+static void
+ephy_window_init (EphyWindow *gs);
+static void
+ephy_window_finalize (GObject *object);
+static void
+ephy_window_show (GtkWidget *widget);
+static void
+ephy_window_notebook_switch_page_cb (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
+ EphyWindow *window);
+
+static void
+ephy_window_tab_detached_cb (EphyNotebook *notebook, gint page,
+ gint x, gint y, gpointer data);
+
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_window_get_type (void)
+{
+ static GType ephy_window_type = 0;
+
+ if (ephy_window_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyWindowClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_window_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyWindow),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_window_init
+ };
+
+ ephy_window_type = g_type_register_static (BONOBO_TYPE_WINDOW,
+ "EphyWindow",
+ &our_info, 0);
+ }
+
+ return ephy_window_type;
+}
+
+static void
+ephy_window_class_init (EphyWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_window_finalize;
+
+ widget_class->show = ephy_window_show;
+}
+
+static
+gboolean
+ephy_window_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ EphyWindow *window)
+{
+ int page;
+
+ if ((event->state & GDK_Shift_L) || (event->state & GDK_Shift_R))
+ return FALSE;
+
+ if ((event->state & GDK_Alt_L) || (event->state & GDK_Alt_R))
+ {
+ page = event->keyval - GDK_0 -1;
+
+ if (page == -1) page = 9;
+
+ if (page>=-1 && page<=9)
+ {
+ gtk_notebook_set_current_page
+ (GTK_NOTEBOOK (window->priv->notebook),
+ page == -1 ? -1 : page);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_window_selection_received_cb (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint time, EphyWindow *window)
+{
+ EphyTab *tab;
+
+ if (selection_data->length <= 0 || selection_data->data == NULL)
+ return;
+
+ tab = ephy_window_get_active_tab (window);
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ selection_data->data, 0);
+}
+
+static void
+save_window_state (GtkWidget *win)
+{
+ EphyWindow *window = EPHY_WINDOW (win);
+
+ if (!(window->priv->chrome_mask & EMBED_CHROME_OPENASPOPUP) &&
+ !(window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN))
+ {
+ ephy_state_save_window (win, "main_window");
+ }
+}
+
+static gboolean
+ephy_window_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ save_window_state (widget);
+ return FALSE;
+}
+
+static gboolean
+ephy_window_state_event_cb (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer data)
+{
+ save_window_state (widget);
+ return FALSE;
+}
+
+static void
+setup_bonobo_window (EphyWindow *window,
+ BonoboUIComponent **ui_component)
+{
+ BonoboWindow *win = BONOBO_WINDOW(window);
+ BonoboUIContainer *container;
+ Bonobo_UIContainer corba_container;
+
+ container = bonobo_window_get_ui_container (win);
+
+ bonobo_ui_engine_config_set_path (bonobo_window_get_ui_engine (win),
+ "/apps/ephy/UIConfig/kvps");
+
+ corba_container = BONOBO_OBJREF (container);
+
+ *ui_component = bonobo_ui_component_new_default ();
+
+ bonobo_ui_component_set_container (*ui_component,
+ corba_container,
+ NULL);
+
+ bonobo_ui_util_set_ui (*ui_component,
+ DATADIR,
+ "epiphany-ui.xml",
+ "ephy", NULL);
+
+ /* Key handling */
+ g_signal_connect(G_OBJECT(win),
+ "key-press-event",
+ G_CALLBACK(ephy_window_key_press_event_cb),
+ window);
+
+ g_signal_connect (G_OBJECT(win), "configure_event",
+ G_CALLBACK (ephy_window_configure_event_cb), NULL);
+ g_signal_connect (G_OBJECT(win), "window_state_event",
+ G_CALLBACK (ephy_window_state_event_cb), NULL);
+
+ g_signal_connect (G_OBJECT(win),
+ "selection-received",
+ G_CALLBACK (ephy_window_selection_received_cb),
+ window);
+}
+
+static EphyEmbedPopupBW *
+setup_popup_factory (EphyWindow *window,
+ BonoboUIComponent *ui_component)
+{
+ EphyEmbedPopupBW *popup;
+
+ popup = ephy_window_get_popup_factory (window);
+ g_object_set_data (G_OBJECT(popup), "EphyWindow", window);
+ bonobo_ui_component_add_verb_list_with_data (ui_component,
+ ephy_popup_verbs,
+ popup);
+
+ return popup;
+}
+
+static GtkNotebook *
+setup_notebook (EphyWindow *window)
+{
+ GtkNotebook *notebook;
+
+ notebook = GTK_NOTEBOOK (ephy_notebook_new ());
+ gtk_notebook_set_scrollable (notebook, TRUE);
+ gtk_notebook_set_show_border (notebook, FALSE);
+ gtk_notebook_set_show_tabs (notebook, FALSE);
+
+ g_signal_connect_after (G_OBJECT (notebook), "switch_page",
+ G_CALLBACK (
+ ephy_window_notebook_switch_page_cb),
+ window);
+
+ g_signal_connect (G_OBJECT (notebook), "tab_detached",
+ G_CALLBACK (ephy_window_tab_detached_cb),
+ NULL);
+
+ gtk_widget_show (GTK_WIDGET (notebook));
+
+ return notebook;
+}
+
+static void
+view_toolbar_changed_cb (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ EphyWindow *window)
+{
+ EmbedChromeMask mask;
+
+ if (window->priv->ignore_layout_toggles) return;
+
+ mask = ephy_window_get_chrome (window);
+ mask ^= EMBED_CHROME_TOOLBARON;
+ ephy_window_set_chrome (window, mask);
+}
+
+static void
+view_statusbar_changed_cb (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ EphyWindow *window)
+{
+ EmbedChromeMask mask;
+
+ if (window->priv->ignore_layout_toggles) return;
+
+ mask = ephy_window_get_chrome (window);
+ mask ^= EMBED_CHROME_STATUSBARON;
+ ephy_window_set_chrome (window, mask);
+}
+
+static void
+view_fullscreen_changed_cb (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ EphyWindow *window)
+{
+ EmbedChromeMask mask;
+
+ if (window->priv->ignore_layout_toggles) return;
+
+ mask = ephy_window_get_chrome (window);
+ mask ^= EMBED_CHROME_OPENASFULLSCREEN;
+ mask |= EMBED_CHROME_DEFAULT;
+ ephy_window_set_chrome (window, mask);
+}
+
+static void
+update_layout_toggles (EphyWindow *window)
+{
+ BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component);
+ EmbedChromeMask mask = window->priv->chrome_mask;
+
+ window->priv->ignore_layout_toggles = TRUE;
+
+ ephy_bonobo_set_toggle_state (ui_component, VIEW_TOOLBAR_PATH,
+ mask & EMBED_CHROME_TOOLBARON);
+ ephy_bonobo_set_toggle_state (ui_component, VIEW_STATUSBAR_PATH,
+ mask & EMBED_CHROME_STATUSBARON);
+ ephy_bonobo_set_toggle_state (ui_component, VIEW_FULLSCREEN_PATH,
+ mask & EMBED_CHROME_OPENASFULLSCREEN);
+
+ window->priv->ignore_layout_toggles = FALSE;
+}
+
+static void
+setup_layout_menus (EphyWindow *window)
+{
+ BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component);
+
+ bonobo_ui_component_add_listener (ui_component, ID_VIEW_TOOLBAR,
+ (BonoboUIListenerFn)view_toolbar_changed_cb,
+ window);
+ bonobo_ui_component_add_listener (ui_component, ID_VIEW_STATUSBAR,
+ (BonoboUIListenerFn)view_statusbar_changed_cb,
+ window);
+ bonobo_ui_component_add_listener (ui_component, ID_VIEW_FULLSCREEN,
+ (BonoboUIListenerFn)view_fullscreen_changed_cb,
+ window);
+}
+
+static void
+ephy_window_init (EphyWindow *window)
+{
+ BonoboUIComponent *ui_component;
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+
+ window->priv = g_new0 (EphyWindowPrivate, 1);
+ window->priv->embed_popup = NULL;
+ window->priv->active_tab = NULL;
+ window->priv->chrome_mask = 0;
+ window->priv->ignore_layout_toggles = FALSE;
+ window->priv->closing = FALSE;
+ window->priv->has_default_size = FALSE;
+
+ /* Setup the window and connect verbs */
+ setup_bonobo_window (window, &ui_component);
+ window->ui_component = G_OBJECT (ui_component);
+ bonobo_ui_component_add_verb_list_with_data (ui_component,
+ ephy_verbs,
+ window);
+ setup_layout_menus (window);
+
+ /* Setup the embed popups factory */
+ window->priv->embed_popup = setup_popup_factory (window,
+ ui_component);
+
+ bonobo_ui_component_freeze (ui_component, NULL);
+
+ /* Setup menubar */
+ ephy_embed_utils_build_charsets_submenu (ui_component,
+ CHARSET_MENU_PATH,
+ (BonoboUIVerbFn)window_cmd_set_charset,
+ window);
+ window->priv->fav_menu = ephy_favorites_menu_new (window);
+ ephy_favorites_menu_set_path (window->priv->fav_menu, GO_FAVORITES_PATH);
+
+ /* Setup toolbar and statusbar */
+ window->priv->toolbar = toolbar_new (window);
+ window->priv->statusbar = statusbar_new (window);
+ window->priv->ppview_toolbar = ppview_toolbar_new (window);
+
+ /* Setup window contents */
+ window->priv->notebook = setup_notebook (window);
+ bonobo_window_set_contents (BONOBO_WINDOW (window),
+ GTK_WIDGET (window->priv->notebook));
+
+ bonobo_ui_component_thaw (ui_component, NULL);
+
+ g_object_ref (ephy_shell);
+
+ /*Once window is fully created, add it to the session list*/
+ session_add_window (session, window);
+}
+
+static void
+save_window_chrome (EphyWindow *window)
+{
+ EmbedChromeMask flags = window->priv->chrome_mask;
+
+ if (flags & EMBED_CHROME_OPENASPOPUP)
+ {
+ }
+ else if (flags & EMBED_CHROME_PPVIEWTOOLBARON)
+ {
+ }
+ else if (flags & EMBED_CHROME_OPENASFULLSCREEN)
+ {
+ eel_gconf_set_boolean (CONF_WINDOWS_FS_SHOW_TOOLBARS,
+ flags & EMBED_CHROME_TOOLBARON);
+ eel_gconf_set_boolean (CONF_WINDOWS_FS_SHOW_STATUSBAR,
+ flags & EMBED_CHROME_STATUSBARON);
+ }
+ else
+ {
+ eel_gconf_set_boolean (CONF_WINDOWS_SHOW_TOOLBARS,
+ flags & EMBED_CHROME_TOOLBARON);
+ eel_gconf_set_boolean (CONF_WINDOWS_SHOW_STATUSBAR,
+ flags & EMBED_CHROME_STATUSBARON);
+ }
+}
+
+static void
+remove_from_session (EphyWindow *window)
+{
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+ g_return_if_fail (session != NULL);
+
+ session_remove_window (session, window);
+}
+
+static void
+ephy_window_finalize (GObject *object)
+{
+ EphyWindow *window;
+
+ g_return_if_fail (IS_EPHY_WINDOW (object));
+
+ window = EPHY_WINDOW (object);
+
+ g_return_if_fail (window->priv != NULL);
+
+ remove_from_session (window);
+
+ if (window->priv->embed_popup)
+ {
+ g_object_unref (G_OBJECT (window->priv->embed_popup));
+ }
+
+ g_object_unref (G_OBJECT (window->priv->toolbar));
+ g_object_unref (G_OBJECT (window->priv->statusbar));
+
+ if (window->priv->find_dialog)
+ {
+ g_object_unref (G_OBJECT (window->priv->find_dialog));
+ }
+
+ if (window->priv->history_dialog)
+ {
+ g_object_remove_weak_pointer
+ (G_OBJECT(window->priv->history_dialog),
+ (gpointer *)&window->priv->history_dialog);
+ }
+
+ g_free (window->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("Ephy Window finalized %p\n", window);
+#endif
+
+ g_object_unref (ephy_shell);
+}
+
+EphyWindow *
+ephy_window_new (void)
+{
+ return EPHY_WINDOW (g_object_new (EPHY_WINDOW_TYPE, NULL));
+}
+
+static void
+dock_item_set_visibility (EphyWindow *window,
+ const char *path,
+ gboolean visibility)
+{
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(window->ui_component),
+ path,
+ !visibility);
+}
+
+EmbedChromeMask
+ephy_window_get_chrome (EphyWindow *window)
+{
+ return window->priv->chrome_mask;
+}
+
+static void
+wmspec_change_state (gboolean add,
+ GdkWindow *window,
+ GdkAtom state1,
+ GdkAtom state2)
+{
+ XEvent xev;
+
+ #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
+ #define _NET_WM_STATE_ADD 1 /* add/set property */
+ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_display;
+ xev.xclient.window = GDK_WINDOW_XID (window);
+ xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = gdk_x11_atom_to_xatom (state1);
+ xev.xclient.data.l[2] = gdk_x11_atom_to_xatom (state2);
+
+ XSendEvent (gdk_display, GDK_WINDOW_XID (gdk_get_default_root_window ()),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+static void
+window_set_fullscreen_mode (EphyWindow *window, gboolean active)
+{
+ GdkWindow *gdk_window;
+
+ gdk_window = GTK_WIDGET(window)->window;
+
+ if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN",
+ FALSE)))
+ {
+ wmspec_change_state (active,
+ gdk_window,
+ gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN",
+ FALSE),
+ GDK_NONE);
+ }
+ else
+ {
+ g_warning ("NET_WM_STATE_FULLSCREEN not supported");
+ }
+}
+
+static void
+translate_default_chrome (EmbedChromeMask *chrome_mask)
+{
+ /* keep only not layout flags */
+ *chrome_mask &= (EMBED_CHROME_WINDOWRAISED |
+ EMBED_CHROME_WINDOWLOWERED |
+ EMBED_CHROME_CENTERSCREEN |
+ EMBED_CHROME_OPENASDIALOG |
+ EMBED_CHROME_OPENASCHROME |
+ EMBED_CHROME_OPENASPOPUP |
+ EMBED_CHROME_OPENASFULLSCREEN);
+
+ /* Load defaults */
+ if (*chrome_mask & EMBED_CHROME_OPENASFULLSCREEN)
+ {
+ if (eel_gconf_get_boolean (CONF_WINDOWS_FS_SHOW_STATUSBAR))
+ {
+ *chrome_mask |= EMBED_CHROME_STATUSBARON;
+ }
+ if (eel_gconf_get_boolean (CONF_WINDOWS_FS_SHOW_TOOLBARS))
+ {
+ *chrome_mask |= EMBED_CHROME_TOOLBARON;
+ }
+ }
+ else
+ {
+ if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_STATUSBAR))
+ {
+ *chrome_mask |= EMBED_CHROME_STATUSBARON;
+ }
+ if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_TOOLBARS))
+ {
+ *chrome_mask |= EMBED_CHROME_TOOLBARON;
+ }
+
+ *chrome_mask |= EMBED_CHROME_PERSONALTOOLBARON;
+ *chrome_mask |= EMBED_CHROME_MENUBARON;
+ }
+}
+
+void
+ephy_window_set_chrome (EphyWindow *window,
+ EmbedChromeMask flags)
+{
+ gboolean toolbar, ppvtoolbar, statusbar;
+
+ if (flags & EMBED_CHROME_DEFAULT)
+ {
+ translate_default_chrome (&flags);
+ }
+
+ dock_item_set_visibility (window, "/menu",
+ flags & EMBED_CHROME_MENUBARON);
+
+ toolbar = (flags & EMBED_CHROME_TOOLBARON) != FALSE;
+ toolbar_set_visibility (window->priv->toolbar,
+ toolbar);
+
+ statusbar = (flags & EMBED_CHROME_STATUSBARON) != FALSE;
+ statusbar_set_visibility (window->priv->statusbar,
+ statusbar);
+
+ ppvtoolbar = (flags & EMBED_CHROME_PPVIEWTOOLBARON) != FALSE;
+ ppview_toolbar_set_old_chrome (window->priv->ppview_toolbar,
+ window->priv->chrome_mask);
+ ppview_toolbar_set_visibility (window->priv->ppview_toolbar,
+ ppvtoolbar);
+
+ /* set fullscreen only when it's really changed */
+ if ((window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN) !=
+ (flags & EMBED_CHROME_OPENASFULLSCREEN))
+ {
+ save_window_chrome (window);
+ window_set_fullscreen_mode (window,
+ flags & EMBED_CHROME_OPENASFULLSCREEN);
+ }
+
+ window->priv->chrome_mask = flags;
+
+ update_layout_toggles (window);
+
+ save_window_chrome (window);
+}
+
+GtkWidget *
+ephy_window_get_notebook (EphyWindow *window)
+{
+ return GTK_WIDGET (window->priv->notebook);
+}
+
+void
+ephy_window_add_tab (EphyWindow *window,
+ EphyTab *tab,
+ gboolean jump_to)
+{
+ GtkWidget *widget;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+ g_return_if_fail (IS_EPHY_TAB (tab));
+
+ ephy_tab_set_window (tab, window);
+
+ widget = GTK_WIDGET(ephy_tab_get_embed (tab));
+
+ ephy_notebook_insert_page (EPHY_NOTEBOOK (window->priv->notebook),
+ widget,
+ EPHY_NOTEBOOK_INSERT_GROUPED,
+ jump_to);
+}
+
+void
+ephy_window_jump_to_tab (EphyWindow *window,
+ EphyTab *tab)
+{
+ GtkWidget *widget;
+ int page;
+
+ widget = GTK_WIDGET(ephy_tab_get_embed (tab));
+
+ page = gtk_notebook_page_num
+ (window->priv->notebook, widget);
+ gtk_notebook_set_current_page
+ (window->priv->notebook, page);
+}
+
+static EphyTab *
+get_tab_from_page_num (GtkNotebook *notebook, gint page_num)
+{
+ EphyTab *tab;
+ GtkWidget *embed_widget;
+
+ if (page_num < 0) return NULL;
+
+ embed_widget = gtk_notebook_get_nth_page (notebook, page_num);
+
+ g_return_val_if_fail (GTK_IS_WIDGET (embed_widget), NULL);
+ tab = g_object_get_data (G_OBJECT (embed_widget), "EphyTab");
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ return tab;
+}
+
+static EphyTab *
+real_get_active_tab (EphyWindow *window, int page_num)
+{
+ if (page_num == -1)
+ {
+ page_num = gtk_notebook_get_current_page (window->priv->notebook);
+ }
+
+ return get_tab_from_page_num (window->priv->notebook, page_num);
+}
+
+void
+ephy_window_remove_tab (EphyWindow *window,
+ EphyTab *tab)
+{
+ GtkWidget *embed;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+ g_return_if_fail (IS_EPHY_TAB (tab));
+
+ window->priv->active_tab = NULL;
+
+ embed = GTK_WIDGET (ephy_tab_get_embed (tab));
+
+ ephy_notebook_remove_page (EPHY_NOTEBOOK (window->priv->notebook),
+ embed);
+}
+
+void
+ephy_window_load_url (EphyWindow *window,
+ const char *url)
+{
+ EphyEmbed *embed;
+
+ g_return_if_fail (IS_EPHY_WINDOW(window));
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+ g_return_if_fail (url != NULL);
+
+ ephy_embed_load_url (embed, url);
+}
+
+void ephy_window_activate_location (EphyWindow *window)
+{
+ toolbar_activate_location (window->priv->toolbar);
+}
+
+void
+ephy_window_show (GtkWidget *widget)
+{
+ EphyWindow *window = EPHY_WINDOW(widget);
+ EphyTab *tab;
+ int w = -1, h = -1;
+
+ if (!window->priv->chrome_mask)
+ {
+ ephy_window_set_chrome (window, EMBED_CHROME_DEFAULT);
+ }
+
+ tab = ephy_window_get_active_tab (window);
+ if (tab) ephy_tab_get_size (tab, &w, &h);
+
+ if (!window->priv->has_default_size && w == -1 && h == -1)
+ {
+ ephy_state_load_window (GTK_WIDGET(window),
+ "main_window",
+ 600, 500, TRUE);
+ window->priv->has_default_size = TRUE;
+ }
+
+ GTK_WIDGET_CLASS (parent_class)->show (widget);
+}
+
+static void
+update_status_message (EphyWindow *window)
+{
+ const char *message;
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ message = ephy_tab_get_status_message (tab);
+ g_return_if_fail (message != NULL);
+
+ statusbar_set_message (STATUSBAR(window->priv->statusbar),
+ message);
+}
+
+static void
+update_progress (EphyWindow *window)
+{
+ EphyTab *tab;
+ int load_percent;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ load_percent = ephy_tab_get_load_percent (tab);
+
+ statusbar_set_progress (STATUSBAR(window->priv->statusbar),
+ load_percent);
+}
+
+static void
+update_security (EphyWindow *window)
+{
+ EphyEmbed *embed;
+ EmbedSecurityLevel level;
+ char *description;
+ char *state = NULL;
+ gboolean secure;
+ char *tooltip;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ if (ephy_embed_get_security_level (embed, &level, &description) != G_OK)
+ {
+ level = STATE_IS_UNKNOWN;
+ description = NULL;
+ }
+
+ secure = FALSE;
+ switch (level)
+ {
+ case STATE_IS_UNKNOWN:
+ state = _("Unknown");
+ break;
+ case STATE_IS_INSECURE:
+ state = _("Insecure");
+ break;
+ case STATE_IS_BROKEN:
+ state = _("Broken");
+ break;
+ case STATE_IS_SECURE_MED:
+ state = _("Medium");
+ secure = TRUE;
+ break;
+ case STATE_IS_SECURE_LOW:
+ state = _("Low");
+ secure = TRUE;
+ break;
+ case STATE_IS_SECURE_HIGH:
+ state = _("High");
+ secure = TRUE;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (description != NULL)
+ {
+ tooltip = g_strdup_printf (_("Security level: %s\n%s"),
+ state, description);
+ g_free (description);
+ }
+ else
+ {
+ tooltip = g_strdup_printf (_("Security level: %s"), state);
+
+ }
+
+ statusbar_set_security_state (STATUSBAR (window->priv->statusbar),
+ secure, tooltip);
+ g_free (tooltip);
+}
+
+static void
+update_nav_control (EphyWindow *window)
+{
+ /* the zoom control is updated at the same time than the navigation
+ controls. This keeps it synched most of the time, but not always,
+ because we don't get a notification when zoom changes */
+
+ gresult back, forward, up, stop;
+ EphyEmbed *embed;
+ EphyTab *tab;
+ gint zoom;
+
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ back = ephy_embed_can_go_back (embed);
+ forward = ephy_embed_can_go_forward (embed);
+ up = ephy_embed_can_go_up (embed);
+ stop = ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED;
+
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_BACK_BUTTON,
+ back == G_OK ? TRUE : FALSE);
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_FORWARD_BUTTON,
+ forward == G_OK ? TRUE : FALSE);
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_UP_BUTTON,
+ up == G_OK ? TRUE : FALSE);
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_STOP_BUTTON,
+ stop);
+ if (ephy_embed_zoom_get (embed, &zoom) == G_OK)
+ {
+ toolbar_set_zoom (window->priv->toolbar, zoom);
+ }
+
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ GO_BACK_CMD_PATH, !back);
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ GO_FORWARD_CMD_PATH, !forward);
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ GO_UP_CMD_PATH, !up);
+}
+
+static void
+update_title_control (EphyWindow *window)
+{
+ EphyTab *tab;
+ const char *title;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ title = ephy_tab_get_title (tab);
+
+ if (title)
+ {
+ gtk_window_set_title (GTK_WINDOW(window),
+ title);
+ }
+}
+
+static void
+update_location_control (EphyWindow *window)
+{
+ EphyTab *tab;
+ const char *location;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ location = ephy_tab_get_location (tab);
+
+ if (!location) location = "";
+
+ toolbar_set_location (window->priv->toolbar,
+ location);
+}
+
+static void
+update_favorites_control (EphyWindow *window)
+{
+ ephy_favorites_menu_update (window->priv->fav_menu);
+}
+
+static void
+update_favicon_control (EphyWindow *window)
+{
+ toolbar_update_favicon (window->priv->toolbar);
+}
+
+static void
+update_find_control (EphyWindow *window)
+{
+ gboolean can_go_next, can_go_prev;
+
+ if (window->priv->find_dialog)
+ {
+ can_go_next = find_dialog_can_go_next
+ (FIND_DIALOG(window->priv->find_dialog));
+ can_go_prev = find_dialog_can_go_prev
+ (FIND_DIALOG(window->priv->find_dialog));
+
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ EDIT_FIND_NEXT_CMD_PATH, can_go_next);
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ EDIT_FIND_PREV_CMD_PATH, can_go_prev);
+ }
+}
+
+static void
+update_window_visibility (EphyWindow *window)
+{
+ GList *l;
+
+ l = ephy_window_get_tabs (window);
+ for (; l != NULL; l = l->next)
+ {
+ EphyTab *tab = EPHY_TAB(l->data);
+ g_return_if_fail (IS_EPHY_TAB(tab));
+
+ if (ephy_tab_get_visibility (tab))
+ {
+ gtk_widget_show (GTK_WIDGET(window));
+ return;
+ }
+ }
+ g_list_free (l);
+
+ if (GTK_WIDGET_VISIBLE (GTK_WIDGET (window)))
+ {
+ gtk_widget_hide (GTK_WIDGET (window));
+ }
+}
+
+static void
+update_spinner_control (EphyWindow *window)
+{
+ GList *l;
+
+ l = ephy_window_get_tabs (window);
+ for (; l != NULL; l = l->next)
+ {
+ EphyTab *tab = EPHY_TAB(l->data);
+ g_return_if_fail (IS_EPHY_TAB(tab));
+
+ if (ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED)
+ {
+ toolbar_spinner_start (window->priv->toolbar);
+ return;
+ }
+ }
+ g_list_free (l);
+
+ toolbar_spinner_stop (window->priv->toolbar);
+}
+
+void
+ephy_window_update_control (EphyWindow *window,
+ ControlID control)
+{
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ switch (control)
+ {
+ case StatusbarMessageControl:
+ update_status_message (window);
+ break;
+ case StatusbarProgressControl:
+ update_progress (window);
+ break;
+ case StatusbarSecurityControl:
+ update_security (window);
+ break;
+ case FindControl:
+ update_find_control (window);
+ break;
+ case ZoomControl:
+ /* the zoom control is updated at the same time than the navigation
+ controls. This keeps it synched most of the time, but not always,
+ because we don't get a notification when zoom changes */
+ case NavControl:
+ update_nav_control (window);
+ break;
+ case TitleControl:
+ update_title_control (window);
+ break;
+ case WindowVisibilityControl:
+ update_window_visibility (window);
+ break;
+ case SpinnerControl:
+ update_spinner_control (window);
+ break;
+ case LocationControl:
+ update_location_control (window);
+ break;
+ case FaviconControl:
+ update_favicon_control (window);
+ break;
+ case FavoritesControl:
+ update_favorites_control (window);
+ break;
+ default:
+ g_warning ("unknown control specified for updating");
+ break;
+ }
+}
+
+void
+ephy_window_update_all_controls (EphyWindow *window)
+{
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ if (ephy_window_get_active_tab (window) != NULL)
+ {
+ update_nav_control (window);
+ update_title_control (window);
+ update_location_control (window);
+ update_favicon_control (window);
+ update_status_message (window);
+ update_progress (window);
+ update_security (window);
+ update_find_control (window);
+ update_spinner_control (window);
+ }
+}
+
+EphyTab *
+ephy_window_get_active_tab (EphyWindow *window)
+{
+ g_return_val_if_fail (IS_EPHY_WINDOW (window), NULL);
+
+ return window->priv->active_tab;
+}
+
+EphyEmbed *
+ephy_window_get_active_embed (EphyWindow *window)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ if (tab)
+ {
+ g_return_val_if_fail (IS_EPHY_WINDOW (G_OBJECT (window)),
+ NULL);
+ return ephy_tab_get_embed (tab);
+ }
+ else return NULL;
+}
+
+EphyEmbedPopupBW *
+ephy_window_get_popup_factory (EphyWindow *window)
+{
+ if (!window->priv->embed_popup)
+ {
+ window->priv->embed_popup = ephy_embed_popup_bw_new
+ (BONOBO_WINDOW(window));
+ ephy_embed_popup_connect_verbs
+ (EPHY_EMBED_POPUP (window->priv->embed_popup),
+ BONOBO_UI_COMPONENT (window->ui_component));
+ }
+
+ return window->priv->embed_popup;
+}
+
+GList *
+ephy_window_get_tabs (EphyWindow *window)
+{
+ GList *tabs = NULL;
+ GtkWidget *w;
+ int i = 0;
+
+ while ((w = gtk_notebook_get_nth_page (window->priv->notebook, i)) != NULL)
+ {
+ EphyTab *tab;
+
+ tab = g_object_get_data (G_OBJECT (w), "EphyTab");
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ tabs = g_list_append (tabs, tab);
+ i++;
+ }
+
+ return tabs;
+}
+
+static void
+save_old_embed_status (EphyTab *tab, EphyWindow *window)
+{
+ /* save old tab location status */
+ ephy_tab_set_location (tab, toolbar_get_location (window->priv->toolbar));
+}
+
+static void
+update_embed_dialogs (EphyWindow *window,
+ EphyTab *tab)
+{
+ EphyEmbed *embed;
+ EphyDialog *find_dialog = window->priv->find_dialog;
+ EphyDialog *history_dialog = window->priv->history_dialog;
+ EphyDialog *history_sidebar = window->priv->history_sidebar;
+
+ embed = ephy_tab_get_embed (tab);
+
+ if (find_dialog)
+ {
+ ephy_embed_dialog_set_embed
+ (EPHY_EMBED_DIALOG(find_dialog),
+ embed);
+ }
+
+ if (history_dialog)
+ {
+ ephy_embed_dialog_set_embed
+ (EPHY_EMBED_DIALOG(history_dialog),
+ embed);
+ }
+
+ if (history_sidebar)
+ {
+ ephy_embed_dialog_set_embed
+ (EPHY_EMBED_DIALOG(history_sidebar),
+ embed);
+ }
+}
+
+static void
+ephy_window_notebook_switch_page_cb (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
+ EphyWindow *window)
+{
+ EphyTab *tab, *old_tab;
+
+ if (window->priv->closing) return;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ /* get the new tab */
+ tab = real_get_active_tab (window, page_num);
+
+ /* update old tab */
+ old_tab = window->priv->active_tab;
+ if (old_tab && tab != old_tab)
+ {
+ g_return_if_fail (IS_EPHY_TAB (G_OBJECT (old_tab)));
+ ephy_tab_set_is_active (old_tab, FALSE);
+ save_old_embed_status (old_tab, window);
+ }
+
+ /* update new tab */
+ window->priv->active_tab = tab;
+ ephy_tab_set_is_active (tab, TRUE);
+
+ update_embed_dialogs (window, tab);
+
+ /* update window controls */
+ ephy_window_update_all_controls (window);
+}
+
+static void
+find_dialog_search_cb (FindDialog *dialog, EphyWindow *window)
+{
+ ephy_window_update_control (window, FindControl);
+}
+
+EphyDialog *
+ephy_window_get_find_dialog (EphyWindow *window)
+{
+ EphyDialog *dialog;
+ EphyEmbed *embed;
+
+ if (window->priv->find_dialog)
+ {
+ return window->priv->find_dialog;
+ }
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_val_if_fail (GTK_IS_WINDOW(window), NULL);
+ dialog = find_dialog_new_with_parent (GTK_WIDGET(window),
+ embed);
+
+ g_signal_connect (dialog, "search",
+ G_CALLBACK (find_dialog_search_cb),
+ window);
+
+ window->priv->find_dialog = dialog;
+
+ return dialog;
+}
+
+void
+ephy_window_show_history (EphyWindow *window)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ window->priv->history_dialog = history_dialog_new_with_parent
+ (GTK_WIDGET(window),
+ embed,
+ FALSE);
+ g_object_add_weak_pointer
+ (G_OBJECT(window->priv->history_dialog),
+ (gpointer *)&window->priv->history_dialog);
+
+ ephy_dialog_show (window->priv->history_dialog);
+}
+
+void
+ephy_window_set_zoom (EphyWindow *window,
+ gint zoom)
+{
+ EphyEmbed *embed;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_zoom_set (embed, zoom, TRUE);
+}
+
+Toolbar *
+ephy_window_get_toolbar (EphyWindow *window)
+{
+ return window->priv->toolbar;
+}
+
+void
+ephy_window_tab_detached_cb (EphyNotebook *notebook, gint page,
+ gint x, gint y, gpointer data)
+{
+ EphyTab *tab;
+ EphyWindow *window;
+ GtkWidget *src_page;
+
+ src_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page);
+ tab = get_tab_from_page_num (GTK_NOTEBOOK (notebook), page);
+ window = ephy_window_new ();
+ ephy_notebook_move_page (notebook,
+ EPHY_NOTEBOOK (ephy_window_get_notebook (window)),
+ src_page, 0);
+ ephy_tab_set_window (tab, window);
+ gtk_widget_show (GTK_WIDGET (window));
+}
diff --git a/src/ephy-window.h b/src/ephy-window.h
new file mode 100644
index 000000000..315cd8cca
--- /dev/null
+++ b/src/ephy-window.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_WINDOW_H
+#define EPHY_WINDOW_H
+
+#include "ephy-embed.h"
+#include "ephy-embed-persist.h"
+#include "ephy-embed-popup-bw.h"
+#include "ephy-dialog.h"
+#include "ephy-notebook.h"
+#include <glib-object.h>
+#include <glib.h>
+#include <bonobo/bonobo-window.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyWindowClass EphyWindowClass;
+
+#define EPHY_WINDOW_TYPE (ephy_window_get_type ())
+#define EPHY_WINDOW(obj) (GTK_CHECK_CAST ((obj), EPHY_WINDOW_TYPE, EphyWindow))
+#define EPHY_WINDOW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_WINDOW, EphyWindowClass))
+#define IS_EPHY_WINDOW(obj) (GTK_CHECK_TYPE ((obj), EPHY_WINDOW_TYPE))
+#define IS_EPHY_WINDOW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_WINDOW))
+
+typedef struct EphyWindow EphyWindow;
+typedef struct EphyWindowPrivate EphyWindowPrivate;
+typedef struct Toolbar Toolbar;
+
+struct EphyWindow
+{
+ BonoboWindow parent;
+ EphyWindowPrivate *priv;
+
+ /* Public to toolbar and statusbar, dont use outside */
+ GObject *ui_component;
+};
+
+struct EphyWindowClass
+{
+ BonoboWindowClass parent_class;
+};
+
+typedef enum
+{
+ NormalMode,
+ FullscreenMode
+} EphyWindowMode;
+
+typedef enum
+{
+ TabsControl,
+ NavControl,
+ FindControl,
+ ZoomControl,
+ CharsetsControl,
+ TitleControl,
+ LocationControl,
+ FaviconControl,
+ StatusbarSecurityControl,
+ StatusbarMessageControl,
+ StatusbarProgressControl,
+ SpinnerControl,
+ WindowVisibilityControl,
+ BMAndHistoryControl,
+ TabsAppeareanceControl,
+ FavoritesControl
+} ControlID;
+
+/* Include the header down here to resolve circular dependency */
+#include "ephy-tab.h"
+
+GType ephy_window_get_type (void);
+
+EphyWindow *ephy_window_new (void);
+
+void ephy_window_set_chrome (EphyWindow *window,
+ EmbedChromeMask chrome_flags);
+
+EmbedChromeMask ephy_window_get_chrome (EphyWindow *window);
+
+GtkWidget *ephy_window_get_notebook (EphyWindow *window);
+
+void ephy_window_add_tab (EphyWindow *window,
+ EphyTab *tab,
+ gboolean jump_to);
+
+void ephy_window_remove_tab (EphyWindow *window,
+ EphyTab *tab);
+
+void ephy_window_jump_to_tab (EphyWindow *window,
+ EphyTab *tab);
+
+void ephy_window_load_url (EphyWindow *window,
+ const char *url);
+
+void ephy_window_set_zoom (EphyWindow *window,
+ gint zoom);
+
+void ephy_window_activate_location (EphyWindow *window);
+
+void ephy_window_update_control (EphyWindow *window,
+ ControlID control);
+
+void ephy_window_update_all_controls (EphyWindow *window);
+
+EphyTab *ephy_window_get_active_tab (EphyWindow *window);
+
+EphyEmbed *ephy_window_get_active_embed (EphyWindow *window);
+
+EphyEmbedPopupBW *ephy_window_get_popup_factory (EphyWindow *window);
+
+GList *ephy_window_get_tabs (EphyWindow *window);
+
+Toolbar *ephy_window_get_toolbar (EphyWindow *window);
+
+/* Dialogs */
+
+EphyDialog *ephy_window_get_find_dialog (EphyWindow *window);
+
+void ephy_window_show_history (EphyWindow *window);
+
+G_END_DECLS
+
+#endif
diff --git a/src/general-prefs.c b/src/general-prefs.c
new file mode 100755
index 000000000..f9eecf4e6
--- /dev/null
+++ b/src/general-prefs.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "general-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-shell.h"
+#include "eel-gconf-extensions.h"
+#include "language-editor.h"
+
+#include <string.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <bonobo/bonobo-i18n.h>
+
+static void general_prefs_class_init (GeneralPrefsClass *klass);
+static void general_prefs_init (GeneralPrefs *dialog);
+static void general_prefs_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+prefs_homepage_current_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog);
+void
+prefs_homepage_blank_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog);
+void
+prefs_language_more_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct GeneralPrefsPrivate
+{
+ gpointer dummy;
+};
+
+enum
+{
+ HOMEPAGE_ENTRY_PROP,
+ NEW_PAGE_PROP,
+ AUTOCHARSET_PROP,
+ DEFAULT_CHARSET_PROP,
+ LANGUAGE_PROP
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { HOMEPAGE_ENTRY_PROP, "homepage_entry", CONF_GENERAL_HOMEPAGE, PT_AUTOAPPLY, NULL },
+ { NEW_PAGE_PROP, "new_page_show_homepage", CONF_GENERAL_NEWPAGE_TYPE, PT_AUTOAPPLY, NULL },
+ { AUTOCHARSET_PROP, "autocharset_optionmenu", CONF_LANGUAGE_AUTODETECT_CHARSET, PT_AUTOAPPLY, NULL },
+ { DEFAULT_CHARSET_PROP, "default_charset_optionmenu", NULL, PT_NORMAL, NULL },
+ { LANGUAGE_PROP, "language_optionmenu", NULL, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+static const
+struct
+{
+ char *name;
+ char *code;
+}
+languages [] =
+{
+ { _("Afrikaans"), "ak" },
+ { _("Albanian"), "sq" },
+ { _("Arabic"), "ar" },
+ { _("Azerbaijani"), "az" },
+ { _("Basque"), "eu" },
+ { _("Breton"), "br" },
+ { _("Bulgarian"), "bg" },
+ { _("Byelorussian"), "be" },
+ { _("Catalan"), "ca" },
+ { _("Chinese"), "zh" },
+ { _("Croatian"), "hr" },
+ { _("Czech"), "cs" },
+ { _("Danish"), "da" },
+ { _("Dutch"), "nl" },
+ { _("English"), "en" },
+ { _("Esperanto"), "eo" },
+ { _("Estonian"), "et" },
+ { _("Faeroese"), "fo" },
+ { _("Finnish"), "fi" },
+ { _("French"), "fr" },
+ { _("Galician"), "gl" },
+ { _("German"), "de" },
+ { _("Greek"), "el" },
+ { _("Hebrew"), "he" },
+ { _("Hungarian"), "hu" },
+ { _("Icelandic"), "is" },
+ { _("Indonesian"), "id" },
+ { _("Irish"), "ga" },
+ { _("Italian"), "it" },
+ { _("Japanese"), "ja" },
+ { _("Korean"), "ko" },
+ { _("Latvian"), "lv" },
+ { _("Lithuanian"), "lt" },
+ { _("Macedonian"), "mk" },
+ { _("Malay"), "ms" },
+ { _("Norwegian/Nynorsk"), "nn" },
+ { _("Norwegian/Bokmaal"), "nb" },
+ { _("Norwegian"), "no" },
+ { _("Polish"), "pl" },
+ { _("Portuguese"), "pt" },
+ { _("Portuguese of Brazil"), "pt-BR" },
+ { _("Romanian"), "ro" },
+ { _("Russian"), "ru" },
+ { _("Scottish"), "gd" },
+ { _("Serbian"), "sr" },
+ { _("Slovak"), "sk" },
+ { _("Slovenian"), "sl" },
+ { _("Spanish"), "es" },
+ { _("Swedish"), "sv" },
+ { _("Tamil"), "ta" },
+ { _("Turkish"), "tr" },
+ { _("Ukrainian"), "uk" },
+ { _("Vietnamian"), "vi" },
+ { _("Walloon"), "wa" },
+ { NULL, NULL }
+};
+
+GType
+general_prefs_get_type (void)
+{
+ static GType general_prefs_type = 0;
+
+ if (general_prefs_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (GeneralPrefsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) general_prefs_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (GeneralPrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) general_prefs_init
+ };
+
+ general_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "GeneralPrefs",
+ &our_info, 0);
+ }
+
+ return general_prefs_type;
+
+}
+
+static void
+general_prefs_class_init (GeneralPrefsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = general_prefs_finalize;
+}
+
+static void
+default_charset_menu_changed_cb (GtkOptionMenu *option_menu,
+ EphyEmbedShell *shell)
+{
+ GList *charsets;
+ int i;
+ CharsetInfo *info;
+
+ ephy_embed_shell_get_charset_titles (shell, NULL, &charsets);
+
+ i = gtk_option_menu_get_history (option_menu);
+ charsets = g_list_nth (charsets, i);
+ g_assert (charsets != NULL);
+ info = (CharsetInfo *) charsets->data;
+ eel_gconf_set_string (CONF_LANGUAGE_DEFAULT_CHARSET,
+ info->name);
+
+ g_list_free (charsets);
+}
+
+static gint
+find_charset_in_list_cmp (gconstpointer a,
+ gconstpointer b)
+{
+ CharsetInfo *info = (CharsetInfo *)a;
+ const char *value = b;
+
+ return (strcmp (info->name, value));
+}
+
+static void
+create_default_charset_menu (GeneralPrefs *dialog)
+{
+ EphyEmbedShell *shell;
+ GList *l;
+ GList *charsets;
+ GtkWidget *menu;
+ GtkWidget *optionmenu;
+ char *value;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_get_charset_titles (shell, NULL, &l);
+
+ menu = gtk_menu_new ();
+
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog),
+ DEFAULT_CHARSET_PROP);
+
+ for (charsets = l; charsets != NULL; charsets = charsets->next)
+ {
+ CharsetInfo *info = (CharsetInfo *) charsets->data;
+ GtkWidget *item;
+
+ item = gtk_menu_item_new_with_label (info->title);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),
+ item);
+ gtk_widget_show (item);
+ }
+
+ gtk_option_menu_set_menu (GTK_OPTION_MENU(optionmenu), menu);
+
+ /* init value */
+ charsets = l;
+ value = eel_gconf_get_string (CONF_LANGUAGE_DEFAULT_CHARSET);
+ charsets = g_list_find_custom (charsets, (gconstpointer)value,
+ (GCompareFunc)find_charset_in_list_cmp);
+ gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu),
+ g_list_position (l, charsets));
+ g_free (value);
+
+ g_signal_connect (optionmenu, "changed",
+ G_CALLBACK (default_charset_menu_changed_cb),
+ shell);
+
+ g_list_free (l);
+}
+
+static GtkWidget *
+general_prefs_new_language_menu (GeneralPrefs *dialog)
+{
+ int i;
+ GtkWidget *menu;
+
+ menu = gtk_menu_new ();
+
+ for (i = 0; languages[i].name != NULL; i++)
+ {
+ GtkWidget *item;
+
+ item = gtk_menu_item_new_with_label (languages[i].name);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),
+ item);
+ gtk_widget_show (item);
+ g_object_set_data (G_OBJECT(item), "desc",
+ languages[i].name);
+ }
+
+ return menu;
+}
+
+static void
+language_menu_changed_cb (GtkOptionMenu *option_menu,
+ gpointer data)
+{
+ GSList *list;
+ GSList *l = NULL;
+ int history;
+
+ list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+ l = g_slist_copy (list);
+
+ /* Subst the first item according to the optionmenu */
+ history = gtk_option_menu_get_history (option_menu);
+ l->data = languages [history].code;
+
+ eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, l);
+
+ g_slist_free (l);
+}
+
+static void
+create_language_menu (GeneralPrefs *dialog)
+{
+ GtkWidget *optionmenu;
+ GtkWidget *menu;
+ const char *value;
+ int i;
+ GSList *list;
+
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog),
+ LANGUAGE_PROP);
+
+ menu = general_prefs_new_language_menu (dialog);
+
+ gtk_option_menu_set_menu (GTK_OPTION_MENU(optionmenu), menu);
+
+ /* init value */
+ list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+ g_return_if_fail (list != NULL);
+ value = (const char *)list->data;
+
+ i = 0;
+ while (languages[i].code && strcmp (languages[i].code, value) != 0)
+ {
+ i++;
+ }
+
+ gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu), i);
+
+ g_signal_connect (optionmenu, "changed",
+ G_CALLBACK (language_menu_changed_cb),
+ NULL);
+}
+
+static void
+general_prefs_init (GeneralPrefs *dialog)
+{
+ dialog->priv = g_new0 (GeneralPrefsPrivate, 1);
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "prefs-dialog.glade",
+ "general_page_box");
+
+ create_default_charset_menu (dialog);
+ create_language_menu (dialog);
+}
+
+static void
+general_prefs_finalize (GObject *object)
+{
+ GeneralPrefs *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_GENERAL_PREFS (object));
+
+ dialog = GENERAL_PREFS (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+general_prefs_new (void)
+{
+ GeneralPrefs *dialog;
+
+ dialog = GENERAL_PREFS (g_object_new (GENERAL_PREFS_TYPE,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+static void
+set_homepage_entry (EphyDialog *dialog,
+ const char *new_location)
+{
+ GtkWidget *entry;
+ int pos;
+
+ entry = ephy_dialog_get_control (dialog, HOMEPAGE_ENTRY_PROP);
+
+ gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+ gtk_editable_insert_text (GTK_EDITABLE (entry), new_location,
+ g_utf8_strlen (new_location, -1),
+ &pos);
+}
+
+void
+prefs_homepage_current_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ EphyWindow *window;
+ EphyTab *tab;
+
+ window = ephy_shell_get_active_window (ephy_shell);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ set_homepage_entry (dialog, ephy_tab_get_location (tab));
+}
+
+void
+prefs_homepage_blank_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ set_homepage_entry (dialog, "about:blank");
+}
+
+static void
+fill_language_editor (LanguageEditor *le)
+{
+ GSList *strings;
+ GSList *tmp;
+ int i;
+
+ /* Fill the list */
+ strings = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+
+ for (tmp = strings; tmp != NULL; tmp = g_slist_next (tmp))
+ {
+ char *value = (char *)tmp->data;
+
+ i = 0;
+ while (languages[i].code && strcmp (languages[i].code, value) != 0)
+ {
+ i++;
+ }
+
+ /* FIXME unsafe, bad prefs could cause it to access random memory */
+ language_editor_add (le, languages[i].name, i);
+ }
+}
+
+static void
+language_dialog_changed_cb (LanguageEditor *le,
+ GSList *list,
+ GeneralPrefs *dialog)
+{
+ GtkWidget *optionmenu;
+ GSList *l = list;
+ GSList *langs = NULL;
+
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog),
+ LANGUAGE_PROP);
+ gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu),
+ (int)(l->data));
+
+ for (; l != NULL; l = l->next)
+ {
+ int i = (int)l->data;
+ langs = g_slist_append (langs, languages[i].code);
+ }
+
+ eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, langs);
+}
+
+void
+prefs_language_more_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ LanguageEditor *editor;
+ GtkWidget *menu;
+ GtkWidget *toplevel;
+
+ menu = general_prefs_new_language_menu (GENERAL_PREFS(dialog));
+
+ toplevel = gtk_widget_get_toplevel (button);
+ editor = language_editor_new (toplevel);
+ language_editor_set_menu (editor, menu);
+ fill_language_editor (editor);
+ ephy_dialog_set_modal (EPHY_DIALOG(editor), TRUE);
+
+ g_signal_connect (editor, "changed",
+ G_CALLBACK(language_dialog_changed_cb),
+ dialog);
+
+ ephy_dialog_show (EPHY_DIALOG(editor));
+}
diff --git a/src/general-prefs.h b/src/general-prefs.h
new file mode 100644
index 000000000..74cfa26a7
--- /dev/null
+++ b/src/general-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GENERAL_PREFS_H
+#define GENERAL_PREFS_H
+
+#include "ephy-embed-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct GeneralPrefs GeneralPrefs;
+typedef struct GeneralPrefsClass GeneralPrefsClass;
+
+#define GENERAL_PREFS_TYPE (general_prefs_get_type ())
+#define GENERAL_PREFS(obj) (GTK_CHECK_CAST ((obj), GENERAL_PREFS_TYPE, GeneralPrefs))
+#define GENERAL_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GENERAL_PREFS, GeneralPrefsClass))
+#define IS_GENERAL_PREFS(obj) (GTK_CHECK_TYPE ((obj), GENERAL_PREFS_TYPE))
+#define IS_GENERAL_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GENERAL_PREFS))
+
+typedef struct GeneralPrefsPrivate GeneralPrefsPrivate;
+
+struct GeneralPrefs
+{
+ EphyDialog parent;
+ GeneralPrefsPrivate *priv;
+};
+
+struct GeneralPrefsClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType general_prefs_get_type (void);
+
+EphyDialog *general_prefs_new (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/history-dialog.c b/src/history-dialog.c
new file mode 100755
index 000000000..4f5b5cc2b
--- /dev/null
+++ b/src/history-dialog.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "history-dialog.h"
+#include "ephy-shell.h"
+#include "ephy-embed-shell.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+#include "ephy-dnd.h"
+#include "ephy-node-filter.h"
+#include "ephy-history-model.h"
+#include "eggtreemodelfilter.h"
+#include "eggtreemultidnd.h"
+#include "ephy-tree-model-sort.h"
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreestore.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <bonobo/bonobo-i18n.h>
+
+#define CONF_HISTORY_SEARCH_TEXT "/apps/epiphany/history/search_text"
+#define CONF_HISTORY_SEARCH_TIME "/apps/epiphany/history/search_time"
+
+static void history_dialog_class_init (HistoryDialogClass *klass);
+static void history_dialog_init (HistoryDialog *dialog);
+static void history_dialog_finalize (GObject *object);
+static void history_dialog_set_embedded (HistoryDialog *d,
+ gboolean embedded);
+
+
+/* Glade callbacks */
+void
+history_host_checkbutton_toggled_cb (GtkWidget *widget,
+ HistoryDialog *dialog);
+void
+history_time_optionmenu_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog);
+void
+history_entry_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog);
+void
+history_ok_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog);
+void
+history_clear_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog);
+
+
+static GObjectClass *parent_class = NULL;
+
+struct HistoryDialogPrivate
+{
+ EphyHistory *gh;
+ EphyNode *root;
+ EphyNode *pages;
+ EphyNodeFilter *filter;
+ GtkTreeView *treeview;
+ GtkTreeModel *model;
+ EphyHistoryModel *nodemodel;
+ GtkTreeModel *filtermodel;
+ EphyTreeModelSort *sortmodel;
+ gboolean group;
+ gboolean embedded;
+};
+
+enum
+{
+ PROP_0,
+ PROP_EMBEDDED
+};
+
+enum
+{
+ PROP_TREEVIEW,
+ PROP_WORD,
+ PROP_TIME
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { PROP_TREEVIEW, "history_treeview", NULL, PT_NORMAL, NULL },
+ { PROP_WORD, "history_entry", CONF_HISTORY_SEARCH_TEXT, PT_NORMAL, NULL },
+ { PROP_TIME, "history_time_optionmenu", CONF_HISTORY_SEARCH_TIME, PT_NORMAL, NULL },
+ { -1, NULL, NULL }
+};
+
+GType
+history_dialog_get_type (void)
+{
+ static GType history_dialog_type = 0;
+
+ if (history_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (HistoryDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) history_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (HistoryDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) history_dialog_init
+ };
+
+ history_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE,
+ "HistoryDialog",
+ &our_info, 0);
+ }
+
+ return history_dialog_type;
+
+}
+
+static void
+history_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ HistoryDialog *d = HISTORY_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBEDDED:
+ history_dialog_set_embedded
+ (d, g_value_get_boolean (value));
+ break;
+ }
+}
+
+static void
+history_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ HistoryDialog *d = HISTORY_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBEDDED:
+ g_value_set_boolean (value, d->priv->embedded);
+ break;
+ }
+}
+
+
+static void
+history_dialog_class_init (HistoryDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = history_dialog_finalize;
+ object_class->set_property = history_dialog_set_property;
+ object_class->get_property = history_dialog_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EMBEDDED,
+ g_param_spec_boolean ("embedded",
+ "Show embedded in another widget",
+ "Show embedded in another widget",
+ TRUE,
+ G_PARAM_READWRITE));
+}
+
+static void
+add_column (HistoryDialog *dialog,
+ const char *title,
+ EphyHistoryModelColumn column)
+{
+ GtkTreeViewColumn *gcolumn;
+ GtkCellRenderer *renderer;
+
+ gcolumn = (GtkTreeViewColumn *) gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (gcolumn, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (gcolumn, renderer,
+ "text", column,
+ NULL);
+ gtk_tree_view_column_set_sizing (gcolumn,
+ GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (gcolumn, column);
+ gtk_tree_view_column_set_title (gcolumn, title);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview),
+ gcolumn);
+}
+
+static void
+history_view_row_activated_cb (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ HistoryDialog *dialog)
+{
+ GtkTreeIter iter, iter2;
+ EphyNode *node;
+ EphyEmbed *embed;
+ const char *location;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->priv->sortmodel), &iter, path);
+ gtk_tree_model_sort_convert_iter_to_child_iter
+ (GTK_TREE_MODEL_SORT (dialog->priv->sortmodel), &iter2, &iter);
+ egg_tree_model_filter_convert_iter_to_child_iter
+ (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel), &iter, &iter2);
+
+ node = ephy_history_model_node_from_iter (dialog->priv->nodemodel, &iter);
+ location = ephy_node_get_property_string (node, EPHY_NODE_PAGE_PROP_LOCATION);
+ g_return_if_fail (location != NULL);
+ embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog));
+ ephy_embed_load_url (embed, location);
+}
+
+static void
+node_from_sort_iter_cb (EphyTreeModelSort *model,
+ GtkTreeIter *iter,
+ void **node,
+ HistoryDialog *dialog)
+{
+ GtkTreeIter filter_iter, node_iter;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
+ &filter_iter, iter);
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel),
+ &node_iter, &filter_iter);
+ *node = ephy_history_model_node_from_iter (EPHY_HISTORY_MODEL (dialog->priv->nodemodel), &node_iter);
+ g_return_if_fail (*node != NULL);
+}
+
+static void
+history_dialog_setup_view (HistoryDialog *dialog)
+{
+ dialog->priv->nodemodel = ephy_history_model_new (dialog->priv->root,
+ dialog->priv->pages,
+ dialog->priv->filter);
+ dialog->priv->filtermodel = egg_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->nodemodel),
+ NULL);
+ egg_tree_model_filter_set_visible_column (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel),
+ EPHY_HISTORY_MODEL_COL_VISIBLE);
+ dialog->priv->sortmodel = EPHY_TREE_MODEL_SORT (
+ ephy_tree_model_sort_new (GTK_TREE_MODEL (dialog->priv->filtermodel)));
+ g_signal_connect_object (G_OBJECT (dialog->priv->sortmodel),
+ "node_from_iter",
+ G_CALLBACK (node_from_sort_iter_cb),
+ dialog,
+ 0);
+ gtk_tree_view_set_model (dialog->priv->treeview,
+ GTK_TREE_MODEL (dialog->priv->sortmodel));
+
+ egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (dialog->priv->treeview));
+ ephy_dnd_enable_model_drag_source (GTK_WIDGET (dialog->priv->treeview));
+
+ add_column (dialog, _("Title"), EPHY_HISTORY_MODEL_COL_TITLE);
+ add_column (dialog, _("Location"), EPHY_HISTORY_MODEL_COL_LOCATION);
+ add_column (dialog, _("Last Visit"), EPHY_HISTORY_MODEL_COL_LAST_VISIT);
+
+ g_signal_connect (dialog->priv->treeview,
+ "row_activated",
+ G_CALLBACK (history_view_row_activated_cb),
+ dialog);
+}
+
+static GTime
+get_date_filter (int filter_type,
+ GTime atime)
+{
+ GDate date, current_date;
+ struct tm tm;
+
+ g_date_clear (&current_date, 1);
+ g_date_set_time (&current_date, time (NULL));
+
+ g_date_clear (&date, 1);
+ g_date_set_time (&date, atime);
+
+ switch (filter_type)
+ {
+ /* Always */
+ case 0:
+ return 0;
+ /* Today */
+ case 1:
+ break;
+ /* Last two days */
+ case 2:
+ g_date_subtract_days (&current_date, 1);
+ break;
+ /* Last three days */
+ case 3:
+ g_date_subtract_days (&current_date, 2);
+ break;
+ /* Week */
+ case 4:
+ g_date_subtract_days (&current_date, 7);
+ break;
+ /* Month */
+ case 5:
+ g_date_subtract_months (&current_date, 1);
+ break;
+ default:
+ break;
+ }
+
+ g_date_to_struct_tm (&current_date, &tm);
+ return mktime (&tm);
+}
+
+static void
+history_dialog_setup_filter (HistoryDialog *dialog)
+{
+ GValue word = {0, };
+ GValue atime = {0, };
+ const char *search_text;
+ GTime date_filter;
+
+ ephy_dialog_get_value (EPHY_DIALOG(dialog), PROP_WORD, &word);
+ search_text = g_value_get_string (&word);
+ ephy_dialog_get_value (EPHY_DIALOG(dialog), PROP_TIME, &atime);
+ date_filter = get_date_filter (g_value_get_int (&atime), time (NULL));
+
+ GDK_THREADS_ENTER ();
+
+ ephy_node_filter_empty (dialog->priv->filter);
+ ephy_node_filter_add_expression (dialog->priv->filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_PAGE_PROP_TITLE,
+ search_text),
+ 0);
+ ephy_node_filter_add_expression (dialog->priv->filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_PAGE_PROP_LOCATION,
+ search_text),
+ 0);
+ ephy_node_filter_add_expression (dialog->priv->filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN,
+ EPHY_NODE_PAGE_PROP_LAST_VISIT,
+ date_filter),
+ 1);
+
+ ephy_node_filter_done_changing (dialog->priv->filter);
+
+ GDK_THREADS_LEAVE ();
+}
+
+static void
+history_dialog_init (HistoryDialog *dialog)
+{
+ EphyEmbedShell *ges;
+
+ dialog->priv = g_new0 (HistoryDialogPrivate, 1);
+
+ ges = ephy_shell_get_embed_shell (ephy_shell);
+ dialog->priv->gh = ephy_embed_shell_get_global_history (ges);
+ g_return_if_fail (dialog->priv->gh != NULL);
+
+ dialog->priv->root = ephy_history_get_hosts (dialog->priv->gh);
+ dialog->priv->pages = ephy_history_get_pages (dialog->priv->gh);
+ dialog->priv->filter = ephy_node_filter_new ();
+}
+
+static void
+history_dialog_set_embedded (HistoryDialog *dialog,
+ gboolean embedded)
+{
+ dialog->priv->embedded = embedded;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "epiphany.glade",
+ embedded ?
+ "history_dock_box" :
+ "history_dialog");
+
+ dialog->priv->treeview = GTK_TREE_VIEW (
+ ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ PROP_TREEVIEW));
+ history_dialog_setup_view (dialog);
+ history_dialog_setup_filter (dialog);
+}
+
+static void
+history_dialog_finalize (GObject *object)
+{
+ HistoryDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_HISTORY_DIALOG (object));
+
+ dialog = HISTORY_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_object_unref (G_OBJECT (dialog->priv->sortmodel));
+ g_object_unref (G_OBJECT (dialog->priv->filtermodel));
+ g_object_unref (G_OBJECT (dialog->priv->nodemodel));
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+history_dialog_new (EphyEmbed *embed,
+ gboolean embedded)
+{
+ HistoryDialog *dialog;
+
+ dialog = HISTORY_DIALOG (g_object_new (HISTORY_DIALOG_TYPE,
+ "embedded", embedded,
+ "EphyEmbed", embed,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+EphyDialog *
+history_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed,
+ gboolean embedded)
+{
+ HistoryDialog *dialog;
+
+ dialog = HISTORY_DIALOG (g_object_new (HISTORY_DIALOG_TYPE,
+ "embedded", embedded,
+ "EphyEmbed", embed,
+ "ParentWindow", window,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+history_entry_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog)
+{
+ if (dialog->priv->treeview == NULL) return;
+ history_dialog_setup_filter (dialog);
+}
+
+void
+history_time_optionmenu_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog)
+{
+ if (dialog->priv->treeview == NULL) return;
+ history_dialog_setup_filter (dialog);
+}
+
+void
+history_ok_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog)
+{
+ g_object_unref (G_OBJECT(dialog));
+}
+
+void
+history_clear_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog)
+{
+ ephy_history_clear (dialog->priv->gh);
+}
diff --git a/src/history-dialog.h b/src/history-dialog.h
new file mode 100644
index 000000000..9a064de5c
--- /dev/null
+++ b/src/history-dialog.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef HISTORY_DIALOG_H
+#define HISTORY_DIALOG_H
+
+#include "ephy-embed-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct HistoryDialog HistoryDialog;
+typedef struct HistoryDialogClass HistoryDialogClass;
+
+#define HISTORY_DIALOG_TYPE (history_dialog_get_type ())
+#define HISTORY_DIALOG(obj) (GTK_CHECK_CAST ((obj), HISTORY_DIALOG_TYPE, HistoryDialog))
+#define HISTORY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), HISTORY_DIALOG, HistoryDialogClass))
+#define IS_HISTORY_DIALOG(obj) (GTK_CHECK_TYPE ((obj), HISTORY_DIALOG_TYPE))
+#define IS_HISTORY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), HISTORY_DIALOG))
+
+typedef struct HistoryDialogPrivate HistoryDialogPrivate;
+
+struct HistoryDialog
+{
+ EphyEmbedDialog parent;
+ HistoryDialogPrivate *priv;
+};
+
+struct HistoryDialogClass
+{
+ EphyEmbedDialogClass parent_class;
+};
+
+GType history_dialog_get_type (void);
+
+EphyDialog *history_dialog_new (EphyEmbed *embed,
+ gboolean embedded);
+
+EphyDialog *history_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed,
+ gboolean embedded);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/language-editor.c b/src/language-editor.c
new file mode 100644
index 000000000..7c24f99fd
--- /dev/null
+++ b/src/language-editor.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "language-editor.h"
+#include "ephy-gui.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include <gtk/gtklabel.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcellrenderertext.h>
+
+enum
+{
+ COL_DESCRIPTION,
+ COL_DATA
+};
+
+enum
+{
+ TREEVIEW_PROP,
+ ADD_PROP,
+ REMOVE_PROP,
+ LANGUAGE_PROP
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { TREEVIEW_PROP, "languages_treeview", NULL, PT_NORMAL, NULL },
+ { ADD_PROP, "add_button", NULL, PT_NORMAL, NULL },
+ { REMOVE_PROP, "remove_button", NULL, PT_NORMAL, NULL },
+ { LANGUAGE_PROP, "languages_optionmenu", NULL, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+
+struct LanguageEditorPrivate
+{
+ GtkWidget *treeview;
+ GtkTreeModel *model;
+ GtkWidget *optionmenu;
+};
+
+enum
+{
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static void
+language_editor_class_init (LanguageEditorClass *klass);
+static void
+language_editor_init (LanguageEditor *ge);
+static void
+language_editor_finalize (GObject *object);
+
+/* Glade callbacks */
+
+void
+language_editor_close_button_cb (GtkWidget *button, EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+static gint signals[LAST_SIGNAL];
+
+GType
+language_editor_get_type (void)
+{
+ static GType language_editor_type = 0;
+
+ if (language_editor_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (LanguageEditorClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) language_editor_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (LanguageEditor),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) language_editor_init
+ };
+
+ language_editor_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "LanguageEditor",
+ &our_info, 0);
+ }
+
+ return language_editor_type;
+
+}
+
+static void
+language_editor_class_init (LanguageEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = language_editor_finalize;
+
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (LanguageEditorClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+}
+
+static void
+language_editor_update_pref (LanguageEditor *editor)
+{
+ GtkTreeIter iter;
+ int index;
+ GSList *strings = NULL;
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (editor->priv->model), &iter))
+ {
+ return;
+ }
+
+ do
+ {
+ GValue val = {0, };
+ gtk_tree_model_get_value (GTK_TREE_MODEL (editor->priv->model),
+ &iter, COL_DATA, &val);
+ index = g_value_get_int (&val);
+
+ strings = g_slist_append(strings, GINT_TO_POINTER(index));
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (editor->priv->model), &iter));
+
+ g_signal_emit (editor, signals[CHANGED], 0, strings);
+
+ g_slist_free (strings);
+}
+
+static void
+language_editor_add_button_clicked_cb (GtkButton *button,
+ LanguageEditor *editor)
+{
+ const char *description;
+ GtkTreeIter iter;
+ GtkWidget *menu;
+ GtkWidget *item;
+ int history;
+
+ history = gtk_option_menu_get_history (GTK_OPTION_MENU(editor->priv->optionmenu));
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(editor->priv->optionmenu));
+ item = gtk_menu_get_active (GTK_MENU(menu));
+ description = (const char *) g_object_get_data (G_OBJECT(item), "desc");
+
+ g_return_if_fail (description != NULL);
+
+ gtk_list_store_append (GTK_LIST_STORE (editor->priv->model),
+ &iter);
+
+ gtk_list_store_set (GTK_LIST_STORE (editor->priv->model),
+ &iter,
+ COL_DESCRIPTION, description,
+ COL_DATA, history,
+ -1);
+
+ language_editor_update_pref (editor);
+}
+
+static void
+language_editor_remove_button_clicked_cb (GtkButton *button,
+ LanguageEditor *editor)
+{
+ GList *l, *r = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(editor->priv->treeview));
+ l = gtk_tree_selection_get_selected_rows (selection, &model);
+ for (;l != NULL; l = l->next)
+ {
+ r = g_list_append (r, gtk_tree_row_reference_new
+ (model, (GtkTreePath *)l->data));
+ }
+
+ for (; r != NULL; r = r->next)
+ {
+ GtkTreePath *node;
+
+ node = gtk_tree_row_reference_get_path
+ ((GtkTreeRowReference *)r->data);
+
+ gtk_tree_model_get_iter (model, &iter, node);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+
+ gtk_tree_row_reference_free ((GtkTreeRowReference *)r->data);
+ }
+
+ l = g_list_first (l);
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+ g_list_free (r);
+
+ language_editor_update_pref (editor);
+}
+
+static void
+language_editor_treeview_drag_end_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ LanguageEditor *editor)
+{
+ language_editor_update_pref (editor);
+}
+
+static void
+language_editor_set_view (LanguageEditor *ge,
+ GtkWidget *treeview,
+ GtkWidget *add_button,
+ GtkWidget *remove_button,
+ GtkWidget *optionmenu)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkListStore *liststore;
+ GtkTreeSelection *selection;
+
+ ge->priv->treeview = treeview;
+ ge->priv->optionmenu = optionmenu;
+
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW(ge->priv->treeview), TRUE);
+
+ liststore = gtk_list_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ ge->priv->model = GTK_TREE_MODEL (liststore);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW(ge->priv->treeview),
+ ge->priv->model);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(ge->priv->treeview),
+ FALSE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(ge->priv->treeview),
+ 0, "Language",
+ renderer,
+ "text", 0,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW(ge->priv->treeview), 0);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_DESCRIPTION);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(ge->priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+
+ /* Connect treeview signals */
+ g_signal_connect
+ (G_OBJECT (ge->priv->treeview),
+ "drag_end",
+ G_CALLBACK(language_editor_treeview_drag_end_cb),
+ ge);
+
+ /* Connect buttons signals */
+ g_signal_connect
+ (G_OBJECT (add_button),
+ "clicked",
+ G_CALLBACK(language_editor_add_button_clicked_cb),
+ ge);
+
+ g_signal_connect
+ (G_OBJECT (remove_button),
+ "clicked",
+ G_CALLBACK(language_editor_remove_button_clicked_cb),
+ ge);
+}
+
+static void
+language_editor_init (LanguageEditor *le)
+{
+ GtkWidget *treeview;
+ GtkWidget *optionmenu;
+ GtkWidget *add_button;
+ GtkWidget *remove_button;
+
+ le->priv = g_new0 (LanguageEditorPrivate, 1);
+
+ ephy_dialog_construct (EPHY_DIALOG(le),
+ properties,
+ "prefs-dialog.glade",
+ "languages_dialog");
+
+ treeview = ephy_dialog_get_control (EPHY_DIALOG(le),
+ TREEVIEW_PROP);
+ add_button = ephy_dialog_get_control (EPHY_DIALOG(le),
+ ADD_PROP);
+ remove_button = ephy_dialog_get_control (EPHY_DIALOG(le),
+ REMOVE_PROP);
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG(le),
+ LANGUAGE_PROP);
+
+ language_editor_set_view (le, treeview, add_button, remove_button,
+ optionmenu);
+}
+
+static void
+language_editor_finalize (GObject *object)
+{
+ LanguageEditor *ge;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_LANGUAGE_EDITOR (object));
+
+ ge = LANGUAGE_EDITOR (object);
+
+ g_return_if_fail (ge->priv != NULL);
+
+ g_free (ge->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+LanguageEditor *
+language_editor_new (GtkWidget *parent)
+{
+ return LANGUAGE_EDITOR (g_object_new (LANGUAGE_EDITOR_TYPE,
+ "ParentWindow", parent,
+ NULL));
+}
+
+void
+language_editor_set_menu (LanguageEditor *editor,
+ GtkWidget *menu)
+{
+ gtk_option_menu_set_menu (GTK_OPTION_MENU(editor->priv->optionmenu),
+ menu);
+}
+
+void
+language_editor_add (LanguageEditor *ge,
+ const char *language,
+ int id)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_append (GTK_LIST_STORE (ge->priv->model),
+ &iter);
+
+ gtk_list_store_set (GTK_LIST_STORE (ge->priv->model),
+ &iter,
+ COL_DESCRIPTION, language,
+ COL_DATA, id,
+ -1);
+}
+
+void
+language_editor_close_button_cb (GtkWidget *button, EphyDialog *dialog)
+{
+ g_object_unref (dialog);
+}
diff --git a/src/language-editor.h b/src/language-editor.h
new file mode 100644
index 000000000..153fa136a
--- /dev/null
+++ b/src/language-editor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef LANGUAGE_EDITOR_H
+#define LANGUAGE_EDITOR_H
+
+#include "general-prefs.h"
+
+#include <gtk/gtkwidget.h>
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct LanguageEditor LanguageEditor;
+typedef struct LanguageEditorClass LanguageEditorClass;
+
+#define LANGUAGE_EDITOR_TYPE (language_editor_get_type ())
+#define LANGUAGE_EDITOR(obj) (GTK_CHECK_CAST ((obj), LANGUAGE_EDITOR_TYPE, LanguageEditor))
+#define LANGUAGE_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), LANGUAGE_EDITOR, LanguageEditorClass))
+#define IS_LANGUAGE_EDITOR(obj) (GTK_CHECK_TYPE ((obj), LANGUAGE_EDITOR_TYPE))
+#define IS_LANGUAGE_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), LANGUAGE_EDITOR))
+
+typedef struct LanguageEditorPrivate LanguageEditorPrivate;
+
+struct LanguageEditor
+{
+ EphyDialog parent;
+ LanguageEditorPrivate *priv;
+};
+
+struct LanguageEditorClass
+{
+ EphyDialogClass parent_class;
+
+ void (* changed) (GSList *languages);
+};
+
+GType language_editor_get_type (void);
+
+LanguageEditor *language_editor_new (GtkWidget *parent);
+
+void language_editor_set_menu (LanguageEditor *editor,
+ GtkWidget *menu);
+
+void language_editor_add (LanguageEditor *editor,
+ const char *language,
+ int id);
+
+G_END_DECLS
+
+#endif
diff --git a/src/pdm-dialog.c b/src/pdm-dialog.c
new file mode 100755
index 000000000..5e077972a
--- /dev/null
+++ b/src/pdm-dialog.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pdm-dialog.h"
+#include "ephy-shell.h"
+#include "ephy-embed-shell.h"
+#include "ephy-gui.h"
+#include "ephy-ellipsizing-label.h"
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <bonobo/bonobo-i18n.h>
+
+typedef struct PdmActionInfo PdmActionInfo;
+
+typedef void (* PDM_add) (PdmActionInfo *info, gpointer data);
+typedef void (* PDM_remove) (PdmActionInfo *info, GList *data);
+typedef void (* PDM_free) (PdmActionInfo *info, GList *data);
+
+static void pdm_dialog_class_init (PdmDialogClass *klass);
+static void pdm_dialog_init (PdmDialog *dialog);
+static void pdm_dialog_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+pdm_dialog_close_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog);
+void
+pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog);
+void
+pdm_dialog_cookies_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmDialog *dialog);
+void
+pdm_dialog_passwords_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct PdmActionInfo
+{
+ PDM_add add;
+ PDM_remove remove;
+ PDM_free free;
+ GtkWidget *treeview;
+ GList *list;
+ int remove_id;
+ int data_col;
+ PdmDialog *dialog;
+};
+
+struct PdmDialogPrivate
+{
+ GtkTreeModel *model;
+ PdmActionInfo *cookies;
+ PdmActionInfo *passwords;
+};
+
+enum
+{
+ PROP_COOKIES_TREEVIEW,
+ PROP_COOKIES_REMOVE,
+ PROP_PASSWORDS_TREEVIEW,
+ PROP_PASSWORDS_REMOVE,
+ PROP_DIALOG,
+ PROP_COOKIES_PROPERTIES
+};
+
+enum
+{
+ COL_COOKIES_HOST,
+ COL_COOKIES_NAME,
+ COL_COOKIES_DATA
+};
+
+enum
+{
+ COL_PASSWORDS_HOST,
+ COL_PASSWORDS_USER,
+ COL_PASSWORDS_DATA
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { PROP_COOKIES_TREEVIEW, "cookies_treeview", NULL, PT_NORMAL, NULL },
+ { PROP_COOKIES_REMOVE, "cookies_remove_button", NULL, PT_NORMAL, NULL },
+ { PROP_PASSWORDS_TREEVIEW, "passwords_treeview", NULL, PT_NORMAL, NULL },
+ { PROP_PASSWORDS_REMOVE, "passwords_remove_button", NULL, PT_NORMAL, NULL },
+ { PROP_DIALOG, "pdm_dialog", NULL, PT_NORMAL, NULL },
+ { PROP_COOKIES_PROPERTIES, "cookies_properties_button", NULL, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+GType
+pdm_dialog_get_type (void)
+{
+ static GType pdm_dialog_type = 0;
+
+ if (pdm_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PdmDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) pdm_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PdmDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) pdm_dialog_init
+ };
+
+ pdm_dialog_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "PdmDialog",
+ &our_info, 0);
+ }
+
+ return pdm_dialog_type;
+
+}
+
+static void
+pdm_dialog_class_init (PdmDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = pdm_dialog_finalize;
+}
+
+static void
+cookies_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmDialog *dialog)
+{
+ GtkWidget *widget;
+ GList *l;
+ EphyDialog *d = EPHY_DIALOG(dialog);
+ gboolean has_selection;
+ GtkTreeModel *model;
+
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+
+ has_selection = l != NULL;
+
+ widget = ephy_dialog_get_control (d, PROP_COOKIES_PROPERTIES);
+ gtk_widget_set_sensitive (widget, has_selection);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+}
+
+static void
+action_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmActionInfo *action)
+{
+ GtkWidget *widget;
+ GList *l;
+ EphyDialog *d = EPHY_DIALOG(action->dialog);
+ gboolean has_selection;
+ GtkTreeModel *model;
+
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+
+ has_selection = l != NULL;
+
+ widget = ephy_dialog_get_control (d, action->remove_id);
+ gtk_widget_set_sensitive (widget, has_selection);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+}
+
+static GtkWidget *
+setup_passwords_treeview (PdmDialog *dialog)
+{
+
+ GtkTreeView *treeview;
+ GtkListStore *liststore;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ treeview = GTK_TREE_VIEW(ephy_dialog_get_control
+ (EPHY_DIALOG(dialog),
+ PROP_PASSWORDS_TREEVIEW));
+
+ /* set tree model */
+ liststore = gtk_list_store_new (3,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(liststore));
+ gtk_tree_view_set_headers_visible (treeview, TRUE);
+ selection = gtk_tree_view_get_selection (treeview);
+ gtk_tree_selection_set_mode (selection,
+ GTK_SELECTION_MULTIPLE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_PASSWORDS_HOST,
+ _("Host"),
+ renderer,
+ "text", COL_PASSWORDS_HOST,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_HOST);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_HOST);
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_PASSWORDS_USER,
+ _("User Name"),
+ renderer,
+ "text", COL_PASSWORDS_USER,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_USER);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_USER);
+
+ return GTK_WIDGET (treeview);
+}
+
+static GtkWidget *
+setup_cookies_treeview (PdmDialog *dialog)
+{
+ GtkTreeView *treeview;
+ GtkListStore *liststore;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ treeview = GTK_TREE_VIEW (ephy_dialog_get_control
+ (EPHY_DIALOG(dialog),
+ PROP_COOKIES_TREEVIEW));
+
+ /* set tree model */
+ liststore = gtk_list_store_new (3,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(liststore));
+ gtk_tree_view_set_headers_visible (treeview, TRUE);
+ selection = gtk_tree_view_get_selection (treeview);
+ gtk_tree_selection_set_mode (selection,
+ GTK_SELECTION_MULTIPLE);
+
+ g_signal_connect (selection, "changed",
+ G_CALLBACK(cookies_treeview_selection_changed_cb),
+ dialog);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_COOKIES_HOST,
+ _("Domain"),
+ renderer,
+ "text", COL_COOKIES_HOST,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_COOKIES_HOST);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_HOST);
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_COOKIES_NAME,
+ _("Name"),
+ renderer,
+ "text", COL_COOKIES_NAME,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_COOKIES_NAME);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_NAME);
+
+ return GTK_WIDGET(treeview);
+}
+
+static void
+pdm_dialog_remove_button_clicked_cb (GtkWidget *button,
+ PdmActionInfo *action)
+{
+ GList *l, *r = NULL;
+ GList *remove_list = NULL;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(action->treeview));
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+ for (;l != NULL; l = l->next)
+ {
+ r = g_list_append (r, gtk_tree_row_reference_new
+ (model, (GtkTreePath *)l->data));
+ }
+
+ for (; r != NULL; r = r->next)
+ {
+ GtkTreeIter iter;
+ gpointer data;
+ GtkTreePath *path;
+ GValue val = {0, };
+
+ path = gtk_tree_row_reference_get_path
+ ((GtkTreeRowReference *)r->data);
+
+ gtk_tree_model_get_iter
+ (model, &iter, path);
+ gtk_tree_model_get_value
+ (model, &iter, action->data_col, &val);
+ data = g_value_get_pointer (&val);
+
+ gtk_list_store_remove (GTK_LIST_STORE(model),
+ &iter);
+
+ action->list = g_list_remove (action->list, data);
+ remove_list = g_list_append (remove_list, data);
+
+ gtk_tree_row_reference_free ((GtkTreeRowReference *)r->data);
+ }
+
+ if (remove_list)
+ {
+ action->remove (action, remove_list);
+ action->free (action, remove_list);
+ }
+
+ l = g_list_first (l);
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+ g_list_free (r);
+}
+
+static void
+setup_action (PdmActionInfo *action)
+{
+ GList *l;
+ GtkWidget *widget;
+ GtkTreeSelection *selection;
+
+ for (l = action->list; l != NULL; l = l->next)
+ {
+ action->add (action, l->data);
+ }
+
+ widget = ephy_dialog_get_control (EPHY_DIALOG(action->dialog),
+ action->remove_id);
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK(pdm_dialog_remove_button_clicked_cb),
+ action);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(action->treeview));
+ g_signal_connect (selection, "changed",
+ G_CALLBACK(action_treeview_selection_changed_cb),
+ action);
+}
+
+static void
+pdm_dialog_cookie_add (PdmActionInfo *info,
+ gpointer cookie)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ CookieInfo *cinfo = (CookieInfo *)cookie;
+
+ store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(info->treeview)));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store,
+ &iter,
+ COL_COOKIES_HOST, cinfo->base.domain,
+ COL_COOKIES_NAME, cinfo->name,
+ COL_COOKIES_DATA, cinfo,
+ -1);
+}
+
+static void
+pdm_dialog_password_add (PdmActionInfo *info,
+ gpointer password)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ PasswordInfo *pinfo = (PasswordInfo *)password;
+
+ store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(info->treeview)));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store,
+ &iter,
+ COL_PASSWORDS_HOST, pinfo->host,
+ COL_PASSWORDS_USER, pinfo->username,
+ COL_PASSWORDS_DATA, pinfo,
+ -1);
+}
+
+static void
+pdm_dialog_cookie_remove (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_remove_cookies (shell, data);
+}
+
+static void
+pdm_dialog_password_remove (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_remove_passwords (shell, data, PASSWORD_PASSWORD);
+}
+
+static void
+pdm_dialog_cookies_free (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ GList *l;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ l = data ? data : info->list;
+ ephy_embed_shell_free_cookies (shell, l);
+}
+
+static void
+pdm_dialog_passwords_free (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ GList *l;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ l = data ? data : info->list;
+ ephy_embed_shell_free_passwords (shell, l);
+}
+
+static void
+pdm_dialog_init (PdmDialog *dialog)
+{
+ EphyEmbedShell *shell;
+ PdmActionInfo *cookies;
+ PdmActionInfo *passwords;
+ GtkWidget *cookies_tv;
+ GtkWidget *passwords_tv;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+
+ dialog->priv = g_new0 (PdmDialogPrivate, 1);
+ dialog->priv->cookies = NULL;
+ dialog->priv->passwords = NULL;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "epiphany.glade",
+ "pdm_dialog");
+
+ cookies_tv = setup_cookies_treeview (dialog);
+ passwords_tv = setup_passwords_treeview (dialog);
+
+ cookies = g_new0 (PdmActionInfo, 1);
+ ephy_embed_shell_list_cookies (shell, &cookies->list);
+ cookies->dialog = dialog;
+ cookies->remove_id = PROP_COOKIES_REMOVE;
+ cookies->add = pdm_dialog_cookie_add;
+ cookies->remove = pdm_dialog_cookie_remove;
+ cookies->free = pdm_dialog_cookies_free;
+ cookies->treeview = cookies_tv;
+ cookies->data_col = COL_COOKIES_DATA;
+ setup_action (cookies);
+
+ passwords = g_new0 (PdmActionInfo, 1);
+ ephy_embed_shell_list_passwords (shell, PASSWORD_PASSWORD,
+ &passwords->list);
+ passwords->dialog = dialog;
+ passwords->remove_id = PROP_PASSWORDS_REMOVE;
+ passwords->add = pdm_dialog_password_add;
+ passwords->remove = pdm_dialog_password_remove;
+ passwords->free = pdm_dialog_passwords_free;
+ passwords->treeview = passwords_tv;
+ passwords->data_col = COL_PASSWORDS_DATA;
+ setup_action (passwords);
+
+ dialog->priv->cookies = cookies;
+ dialog->priv->passwords = passwords;
+}
+
+static void
+pdm_dialog_finalize (GObject *object)
+{
+ PdmDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PDM_DIALOG (object));
+
+ dialog = PDM_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ pdm_dialog_passwords_free (dialog->priv->passwords, NULL);
+ pdm_dialog_cookies_free (dialog->priv->cookies, NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+pdm_dialog_new (GtkWidget *window)
+{
+ PdmDialog *dialog;
+
+ dialog = PDM_DIALOG (g_object_new (PDM_DIALOG_TYPE,
+ "ParentWindow", window,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+static void
+show_cookies_properties (PdmDialog *dialog,
+ CookieInfo *info)
+{
+ GtkWidget *gdialog;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *parent;
+ GtkWidget *dialog_vbox;
+
+ parent = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ PROP_DIALOG);
+
+ gdialog = gtk_dialog_new_with_buttons
+ (_("Cookie properties"),
+ GTK_WINDOW(parent),
+ GTK_DIALOG_MODAL,
+ GTK_STOCK_CLOSE, 0, NULL);
+ gtk_dialog_set_has_separator (GTK_DIALOG(gdialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER(gdialog), 6);
+
+ table = gtk_table_new (2, 4, FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER(table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE(table), 10);
+ gtk_table_set_col_spacings (GTK_TABLE(table), 10);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (_("<b>Value</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = ephy_ellipsizing_label_new (info->value);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 0, 1);
+
+ label = gtk_label_new (_("<b>Path</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (info->path);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 1, 2);
+
+ label = gtk_label_new (_("<b>Secure</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (info->secure);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 2, 3);
+
+ label = gtk_label_new (_("<b>Expire</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (info->expire);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0.5);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 3, 4);
+
+ dialog_vbox = GTK_DIALOG(gdialog)->vbox;
+ gtk_box_pack_start (GTK_BOX(dialog_vbox),
+ table,
+ FALSE, FALSE, 0);
+
+ gtk_dialog_run (GTK_DIALOG(gdialog));
+
+ gtk_widget_destroy (gdialog);
+}
+
+void
+pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog)
+{
+ GtkTreeModel *model;
+ GValue val = {0, };
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ CookieInfo *info;
+ GList *l;
+ GtkWidget *treeview = dialog->priv->cookies->treeview;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+
+ path = (GtkTreePath *)l->data;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get_value
+ (model, &iter, COL_COOKIES_DATA, &val);
+ info = (CookieInfo *)g_value_get_pointer (&val);
+
+ show_cookies_properties (dialog, info);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+}
+
+void
+pdm_dialog_close_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog)
+{
+ g_object_unref (dialog);
+}
diff --git a/src/pdm-dialog.h b/src/pdm-dialog.h
new file mode 100644
index 000000000..7216d4ac0
--- /dev/null
+++ b/src/pdm-dialog.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PDM_DIALOG_H
+#define PDM_DIALOG_H
+
+#include "ephy-dialog.h"
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct PdmDialog PdmDialog;
+typedef struct PdmDialogClass PdmDialogClass;
+
+#define PDM_DIALOG_TYPE (pdm_dialog_get_type ())
+#define PDM_DIALOG(obj) (GTK_CHECK_CAST ((obj), PDM_DIALOG_TYPE, PdmDialog))
+#define PDM_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PDM_DIALOG, PdmDialogClass))
+#define IS_PDM_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PDM_DIALOG_TYPE))
+#define IS_PDM_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PDM_DIALOG))
+
+typedef struct PdmDialogPrivate PdmDialogPrivate;
+
+struct PdmDialog
+{
+ EphyDialog parent;
+ PdmDialogPrivate *priv;
+};
+
+struct PdmDialogClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType pdm_dialog_get_type (void);
+
+EphyDialog *pdm_dialog_new (GtkWidget *window);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/popup-commands.c b/src/popup-commands.c
new file mode 100644
index 000000000..bf187d981
--- /dev/null
+++ b/src/popup-commands.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "popup-commands.h"
+#include "ephy-shell.h"
+
+static EphyWindow *
+get_window_from_popup (EphyEmbedPopup *popup)
+{
+ return EPHY_WINDOW (g_object_get_data(G_OBJECT(popup), "EphyWindow"));
+}
+
+void popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ GValue *value;
+
+ tab = ephy_window_get_active_tab (get_window_from_popup (popup));
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "link", &value);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_NEW_WINDOW);
+}
+
+void popup_cmd_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ EphyWindow *window;
+ GValue *value;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "link", &value);
+
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW);
+}
+
+void popup_cmd_image_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ EphyWindow *window;
+ GValue *value;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "image", &value);
+
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW);
+}
+
+void popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ GValue *value;
+
+ tab = ephy_window_get_active_tab (get_window_from_popup (popup));
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "image", &value);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_NEW_WINDOW);
+}
+
+void popup_cmd_add_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ GtkWidget *new_bookmark;
+ EphyBookmarks *bookmarks;
+ EphyEmbedEvent *info = ephy_embed_popup_get_event (popup);
+ EphyEmbed *embed;
+ GtkWidget *window;
+ GValue *link_title;
+ GValue *link_rel;
+ GValue *link;
+ GValue *link_is_smart;
+ const char *title;
+ const char *location;
+ const char *rel;
+ gboolean is_smart;
+
+ embed = ephy_embed_popup_get_embed (popup);
+ window = gtk_widget_get_toplevel (GTK_WIDGET (embed));
+
+ ephy_embed_event_get_property (info, "link_is_smart", &link_is_smart);
+ ephy_embed_event_get_property (info, "link", &link);
+ ephy_embed_event_get_property (info, "link_title", &link_title);
+ ephy_embed_event_get_property (info, "link_rel", &link_rel);
+
+ title = g_value_get_string (link_title);
+ location = g_value_get_string (link);
+ rel = g_value_get_string (link_rel);
+ is_smart = g_value_get_int (link_is_smart);
+
+ g_return_if_fail (location);
+
+ if (!title || !title[0])
+ {
+ title = location;
+ }
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ new_bookmark = ephy_new_bookmark_new
+ (bookmarks, GTK_WINDOW (window), location);
+ ephy_new_bookmark_set_title
+ (EPHY_NEW_BOOKMARK (new_bookmark), title);
+ ephy_new_bookmark_set_smarturl
+ (EPHY_NEW_BOOKMARK (new_bookmark), rel);
+ gtk_widget_show (new_bookmark);
+}
+
+void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyTab *tab;
+ EphyWindow *window;
+ EphyEmbed *embed;
+ char *location;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ embed = ephy_window_get_active_embed (window);
+
+ ephy_embed_get_location (embed, FALSE, FALSE, &location);
+
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ location,
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW);
+
+ g_free (location);
+}
+
+void popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyTab *tab;
+ EphyEmbed *embed;
+ EphyWindow *window;
+ char *location;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ embed = ephy_window_get_active_embed (window);
+
+ ephy_embed_get_location (embed, FALSE, FALSE, &location);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab,
+ location,
+ EPHY_NEW_TAB_IN_NEW_WINDOW);
+
+ g_free (location);
+}
+
+void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ /* FIXME implement */
+}
+
+void popup_cmd_view_source (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ /* FIXME implement */
+}
diff --git a/src/popup-commands.h b/src/popup-commands.h
new file mode 100644
index 000000000..e5b369c76
--- /dev/null
+++ b/src/popup-commands.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-popup.h"
+#include "ephy-new-bookmark.h"
+
+#include <bonobo/bonobo-ui-component.h>
+
+void popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_image_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_add_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_view_source (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
diff --git a/src/ppview-toolbar.c b/src/ppview-toolbar.c
new file mode 100755
index 000000000..06b2cbb6e
--- /dev/null
+++ b/src/ppview-toolbar.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "ppview-toolbar.h"
+#include "ephy-window.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+
+#include <string.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-ui-toolbar-button-item.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkmenu.h>
+
+#define PPV_GOTO_FIRST_PATH "/commands/PPVGotoFirst"
+#define PPV_GOTO_LAST_PATH "/commands/PPVGotoLast"
+#define PPV_GO_BACK_PATH "/commands/PPVGoBack"
+#define PPV_GO_FORWARD_PATH "/commands/PPVGoForward"
+
+static void ppview_toolbar_class_init (PPViewToolbarClass *klass);
+static void ppview_toolbar_init (PPViewToolbar *t);
+static void ppview_toolbar_finalize (GObject *object);
+static void ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window);
+static void
+ppview_toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+ppview_toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+static GObjectClass *parent_class = NULL;
+
+struct PPViewToolbarPrivate
+{
+ EphyWindow *window;
+ BonoboUIComponent *ui_component;
+ gboolean visibility;
+ EmbedChromeMask old_chrome;
+ int current_page;
+};
+
+static void
+toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_go_back (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_close (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+BonoboUIVerb ppview_toolbar_verbs [] = {
+ BONOBO_UI_VERB ("PPVGotoFirst", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_first),
+ BONOBO_UI_VERB ("PPVGotoLast", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_last),
+ BONOBO_UI_VERB ("PPVGoBack", (BonoboUIVerbFn)toolbar_cmd_ppv_go_back),
+ BONOBO_UI_VERB ("PPVGoForward", (BonoboUIVerbFn)toolbar_cmd_ppv_go_forward),
+ BONOBO_UI_VERB ("PPVClose", (BonoboUIVerbFn)toolbar_cmd_ppv_close),
+
+ BONOBO_UI_VERB_END
+};
+
+GType
+ppview_toolbar_get_type (void)
+{
+ static GType ppview_toolbar_type = 0;
+
+ if (ppview_toolbar_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PPViewToolbarClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ppview_toolbar_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PPViewToolbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ppview_toolbar_init
+ };
+
+ ppview_toolbar_type = g_type_register_static (G_TYPE_OBJECT,
+ "PPViewToolbar",
+ &our_info, 0);
+ }
+
+ return ppview_toolbar_type;
+
+}
+
+static void
+ppview_toolbar_class_init (PPViewToolbarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ppview_toolbar_finalize;
+
+ object_class->set_property = ppview_toolbar_set_property;
+ object_class->get_property = ppview_toolbar_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+ppview_toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PPViewToolbar *t = PPVIEW_TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ ppview_toolbar_set_window (t, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+ppview_toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PPViewToolbar *t = PPVIEW_TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, t->priv->window);
+ break;
+ }
+}
+
+static void
+ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window)
+{
+ g_return_if_fail (t->priv->window == NULL);
+
+ t->priv->window = window;
+ t->priv->ui_component = BONOBO_UI_COMPONENT
+ (t->priv->window->ui_component);
+
+ bonobo_ui_component_add_verb_list_with_data (t->priv->ui_component,
+ ppview_toolbar_verbs,
+ t);
+}
+
+static void
+ppview_toolbar_init (PPViewToolbar *t)
+{
+ t->priv = g_new0 (PPViewToolbarPrivate, 1);
+
+ t->priv->window = NULL;
+ t->priv->ui_component = NULL;
+ t->priv->visibility = TRUE;
+}
+
+static void
+ppview_toolbar_finalize (GObject *object)
+{
+ PPViewToolbar *t;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PPVIEW_TOOLBAR (object));
+
+ t = PPVIEW_TOOLBAR (object);
+
+ g_return_if_fail (t->priv != NULL);
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+PPViewToolbar *
+ppview_toolbar_new (EphyWindow *window)
+{
+ PPViewToolbar *t;
+
+ t = PPVIEW_TOOLBAR (g_object_new (PPVIEW_TOOLBAR_TYPE,
+ "EphyWindow", window,
+ NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+void
+ppview_toolbar_set_old_chrome (PPViewToolbar *t,
+ EmbedChromeMask chrome)
+{
+ t->priv->old_chrome = chrome;
+}
+
+static void
+toolbar_update_sensitivity (PPViewToolbar *t)
+{
+ int pages, c_page;
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_num_pages (embed, &pages);
+ c_page = t->priv->current_page;
+
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GO_BACK_PATH, c_page > 1);
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GOTO_FIRST_PATH, c_page > 1);
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GO_FORWARD_PATH, c_page < pages);
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GOTO_LAST_PATH, c_page < pages);
+}
+
+void
+ppview_toolbar_set_visibility (PPViewToolbar *t, gboolean visibility)
+{
+ if (visibility == t->priv->visibility) return;
+
+ t->priv->visibility = visibility;
+
+ if (visibility)
+ {
+ t->priv->current_page = 1;
+ toolbar_update_sensitivity (t);
+ }
+
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component),
+ "/PrintPreview",
+ !visibility);
+}
+
+static void
+toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed, PRINTPREVIEW_HOME, 0);
+
+ t->priv->current_page = 1;
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed,
+ PRINTPREVIEW_END,
+ 0);
+
+ ephy_embed_print_preview_num_pages (embed,
+ &t->priv->current_page);
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_go_back (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed,
+ PRINTPREVIEW_PREV_PAGE,
+ 0);
+
+ t->priv->current_page --;
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed,
+ PRINTPREVIEW_NEXT_PAGE,
+ 0);
+
+ t->priv->current_page ++;
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_close (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_window_set_chrome (window, t->priv->old_chrome);
+
+ ephy_embed_print_preview_close (embed);
+
+ toolbar_update_sensitivity (t);
+}
+
diff --git a/src/ppview-toolbar.h b/src/ppview-toolbar.h
new file mode 100644
index 000000000..3e6a4b504
--- /dev/null
+++ b/src/ppview-toolbar.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PPVIEW_TOOLBAR_H
+#define PPVIEW_TOOLBAR_H
+
+#include "ephy-window.h"
+#include <glib-object.h>
+#include <glib.h>
+#include <gtk/gtkbutton.h>
+
+G_BEGIN_DECLS
+
+typedef struct PPViewToolbar PPViewToolbar;
+typedef struct PPViewToolbarClass PPViewToolbarClass;
+
+#define PPVIEW_TOOLBAR_TYPE (ppview_toolbar_get_type ())
+#define PPVIEW_TOOLBAR(obj) (GTK_CHECK_CAST ((obj), PPVIEW_TOOLBAR_TYPE, PPViewToolbar))
+#define PPVIEW_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PPVIEW_TOOLBAR, PPViewToolbarClass))
+#define IS_PPVIEW_TOOLBAR(obj) (GTK_CHECK_TYPE ((obj), PPVIEW_TOOLBAR_TYPE))
+#define IS_PPVIEW_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PPVIEW_TOOLBAR))
+
+typedef struct PPViewToolbarPrivate PPViewToolbarPrivate;
+
+struct PPViewToolbar
+{
+ GObject parent;
+ PPViewToolbarPrivate *priv;
+};
+
+struct PPViewToolbarClass
+{
+ GObjectClass parent_class;
+};
+
+GType ppview_toolbar_get_type (void);
+
+PPViewToolbar *ppview_toolbar_new (EphyWindow *window);
+
+void ppview_toolbar_set_visibility (PPViewToolbar *t,
+ gboolean visibility);
+
+void ppview_toolbar_set_old_chrome (PPViewToolbar *t,
+ EmbedChromeMask chrome);
+
+G_END_DECLS
+
+#endif
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
new file mode 100644
index 000000000..8f010420c
--- /dev/null
+++ b/src/prefs-dialog.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "prefs-dialog.h"
+#include "general-prefs.h"
+#include "appearance-prefs.h"
+#include "ui-prefs.h"
+#include "ephy-dialog.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-state.h"
+
+#include <bonobo/bonobo-i18n.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkradiobutton.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+
+static void
+prefs_dialog_class_init (PrefsDialogClass *klass);
+static void
+prefs_dialog_init (PrefsDialog *pd);
+static void
+prefs_dialog_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+prefs_proxy_auto_url_reload_cb (GtkWidget *button,
+ EphyDialog *dialog);
+void
+prefs_clear_memory_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data);
+void
+prefs_clear_disk_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data);
+
+
+/* Proxy page */
+
+enum
+{
+ CACHE_COMPARE_PROP,
+ DISK_CACHE_PROP,
+ MEMORY_CACHE_PROP
+};
+
+static const
+EphyDialogProperty network_properties [] =
+{
+ { CACHE_COMPARE_PROP, "cache_compare_radiobutton", CONF_NETWORK_CACHE_COMPARE, PT_AUTOAPPLY, NULL },
+ { DISK_CACHE_PROP, "disk_cache_spin", CONF_NETWORK_DISK_CACHE, PT_AUTOAPPLY, NULL },
+ { MEMORY_CACHE_PROP, "memory_cache_spin", CONF_NETWORK_MEMORY_CACHE, PT_AUTOAPPLY, NULL },
+
+ { -1, NULL, NULL }
+};
+
+struct PrefsDialogPrivate
+{
+ GtkWidget *notebook;
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+prefs_dialog_get_type (void)
+{
+ static GType prefs_dialog_type = 0;
+
+ if (prefs_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PrefsDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) prefs_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PrefsDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) prefs_dialog_init
+ };
+
+ prefs_dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
+ "PrefsDialog",
+ &our_info, 0);
+ }
+
+ return prefs_dialog_type;
+
+}
+
+GtkDialog *
+prefs_dialog_new (void)
+{
+ GtkDialog *dialog;
+
+ dialog = GTK_DIALOG (g_object_new (PREFS_DIALOG_TYPE, NULL));
+
+ return dialog;
+}
+
+static void
+prefs_dialog_class_init (PrefsDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = prefs_dialog_finalize;
+}
+
+static void
+prefs_dialog_finalize (GObject *object)
+{
+ PrefsDialog *pd;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PREFS_DIALOG (object));
+
+ pd = PREFS_DIALOG (object);
+
+ g_return_if_fail (pd->priv != NULL);
+
+ g_free (pd->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static EphyDialog *
+create_page (PrefsPageID id,
+ const char *page_widget,
+ const EphyDialogProperty *prop)
+{
+ EphyDialog *page = NULL;
+
+ switch (id)
+ {
+ case PREFS_PAGE_GENERAL:
+ page = general_prefs_new ();
+ break;
+ case PREFS_PAGE_APPEARANCE:
+ page = appearance_prefs_new ();
+ break;
+ case PREFS_PAGE_UI:
+ page = ui_prefs_new ();
+ break;
+ case PREFS_PAGE_ADVANCED:
+ page = ephy_dialog_new ();
+ ephy_dialog_construct (EPHY_DIALOG(page),
+ prop,
+ "prefs-dialog.glade",
+ page_widget);
+ break;
+ }
+
+ return page;
+}
+
+static EphyDialog *
+prefs_dialog_get_page (PrefsDialog *pd,
+ PrefsPageID id)
+{
+ const char *page_widget = NULL;
+ EphyDialog *page;
+ const EphyDialogProperty *prop = NULL;
+
+ switch (id)
+ {
+ case PREFS_PAGE_APPEARANCE:
+ page_widget = "appearance_page_box";
+ break;
+ case PREFS_PAGE_GENERAL:
+ page_widget = "general_page_box";
+ break;
+ case PREFS_PAGE_UI:
+ page_widget = "ui_page_box";
+ break;
+ case PREFS_PAGE_ADVANCED:
+ page_widget = "network_page_box";
+ prop = network_properties;
+ break;
+ }
+
+ g_assert (page_widget != NULL);
+
+ page = create_page (id, page_widget, prop);
+ g_assert (page != NULL);
+
+ return page;
+}
+
+void
+prefs_dialog_show_page (PrefsDialog *pd,
+ PrefsPageID id)
+{
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (pd->priv->notebook), id);
+}
+
+static void
+prefs_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer data)
+{
+ if (response_id == GTK_RESPONSE_CLOSE)
+ {
+ gtk_widget_destroy (GTK_WIDGET(dialog));
+ }
+}
+
+static void
+prefs_build_notebook (PrefsDialog *pd)
+{
+ int i;
+ GtkWidget *nb;
+
+ struct
+ {
+ char *name;
+ int id;
+ }
+ pages[] =
+ {
+ { _("General"), PREFS_PAGE_GENERAL },
+ { _("Appearance"), PREFS_PAGE_APPEARANCE },
+ { _("User Interface"), PREFS_PAGE_UI },
+ { _("Advanced"), PREFS_PAGE_ADVANCED },
+
+ { NULL, 0 }
+ };
+
+ gtk_dialog_add_button (GTK_DIALOG (pd), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+
+ g_signal_connect (pd, "response",
+ G_CALLBACK (prefs_dialog_response_cb),
+ NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (pd), 5);
+
+ nb = gtk_notebook_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (nb), 5);
+ gtk_widget_show (nb);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (pd)->vbox), nb);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), TRUE);
+ pd->priv->notebook = nb;
+
+ for (i = 0; pages[i].name != NULL; i++)
+ {
+ GtkWidget *label, *child;
+ EphyDialog *page;
+
+ page = prefs_dialog_get_page (pd, pages[i].id);
+
+ child = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (child);
+ label = gtk_label_new (pages[i].name);
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb),
+ child, label);
+
+ ephy_dialog_show_embedded (page, child);
+ }
+}
+
+static gboolean
+prefs_dialog_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ ephy_state_save_window (widget, "prefs_dialog");
+
+ return FALSE;
+}
+
+static void
+prefs_dialog_init (PrefsDialog *pd)
+{
+ pd->priv = g_new0 (PrefsDialogPrivate, 1);
+
+ gtk_window_set_title (GTK_WINDOW(pd), _("Preferences"));
+ gtk_dialog_set_has_separator (GTK_DIALOG(pd), FALSE);
+
+ ephy_state_load_window (GTK_WIDGET(pd),
+ "prefs_dialog", -1, -1, FALSE);
+
+ g_signal_connect (pd,
+ "configure_event",
+ G_CALLBACK (prefs_dialog_configure_event_cb),
+ NULL);
+
+ prefs_build_notebook (pd);
+}
+
+/* Network page callbacks */
+
+void
+prefs_clear_memory_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data)
+{
+ EphyEmbedShell *shell;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_clear_cache (shell, MEMORY_CACHE);
+}
+
+void
+prefs_clear_disk_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data)
+{
+ EphyEmbedShell *shell;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_clear_cache (shell, DISK_CACHE);
+}
diff --git a/src/prefs-dialog.h b/src/prefs-dialog.h
new file mode 100644
index 000000000..3c5528b2f
--- /dev/null
+++ b/src/prefs-dialog.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PREFS_DIALOG_H
+#define PREFS_DIALOG_H
+
+#include <gtk/gtkdialog.h>
+#include <glib-object.h>
+#include <glib.h>
+
+typedef struct PrefsDialog PrefsDialog;
+typedef struct PrefsDialogClass PrefsDialogClass;
+
+#define PREFS_DIALOG_TYPE (prefs_dialog_get_type ())
+#define PREFS_DIALOG(obj) (GTK_CHECK_CAST ((obj), PREFS_DIALOG_TYPE, PrefsDialog))
+#define PREFS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PREFS_DIALOG, PrefsDialogClass))
+#define IS_PREFS_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PREFS_DIALOG_TYPE))
+#define IS_PREFS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PREFS_DIALOG))
+
+typedef struct PrefsDialogPrivate PrefsDialogPrivate;
+
+typedef enum
+{
+ PREFS_PAGE_GENERAL,
+ PREFS_PAGE_APPEARANCE,
+ PREFS_PAGE_UI,
+ PREFS_PAGE_ADVANCED
+} PrefsPageID;
+
+struct PrefsDialog
+{
+ GtkDialog parent;
+ PrefsDialogPrivate *priv;
+};
+
+struct PrefsDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+GType prefs_dialog_get_type (void);
+
+GtkDialog *prefs_dialog_new (void);
+
+void prefs_dialog_show_page (PrefsDialog *pd,
+ PrefsPageID id);
+
+#endif
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 000000000..920b49df9
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "session.h"
+#include "ephy-shell.h"
+#include "ephy-tab.h"
+#include "ephy-window.h"
+#include "ephy-prefs.h"
+#include "ephy-string.h"
+#include "ephy-file-helpers.h"
+#include "eel-gconf-extensions.h"
+
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <libgnomeui/gnome-client.h>
+
+enum
+{
+ RESTORE_TYPE_PROP
+};
+
+enum
+{
+ RESTORE_SESSION,
+ RESTORE_AS_BOOKMARKS,
+ DISCARD_SESSION
+};
+
+static void session_class_init (SessionClass *klass);
+static void session_init (Session *t);
+static void session_finalize (GObject *object);
+static void session_dispose (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+struct SessionPrivate
+{
+ GList *windows;
+ gboolean dont_remove_crashed;
+};
+
+enum
+{
+ NEW_WINDOW,
+ CLOSE_WINDOW,
+ LAST_SIGNAL
+};
+
+static guint session_signals[LAST_SIGNAL] = { 0 };
+
+GType
+session_get_type (void)
+{
+ static GType session_type = 0;
+
+ if (session_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (SessionClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) session_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (Session),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) session_init
+ };
+
+ session_type = g_type_register_static (G_TYPE_OBJECT,
+ "Session",
+ &our_info, 0);
+ }
+
+ return session_type;
+
+}
+
+static void
+session_class_init (SessionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = session_finalize;
+ object_class->dispose = session_dispose;
+
+ session_signals[NEW_WINDOW] =
+ g_signal_new ("new_window",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SessionClass, new_window),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_OBJECT);
+
+ session_signals[CLOSE_WINDOW] =
+ g_signal_new ("close_window",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SessionClass, close_window),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static char *
+get_session_filename (const char *filename)
+{
+ char *save_to;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ if (strcmp (filename, SESSION_CRASHED) == 0)
+ {
+ save_to = g_build_filename (ephy_dot_dir (),
+ "session_crashed.xml",
+ NULL);
+ }
+ else if (strcmp (filename, SESSION_GNOME) == 0)
+ {
+ char *tmp;
+
+ save_to = g_build_filename (ephy_dot_dir (),
+ "session_gnome-XXXXXX",
+ NULL);
+ tmp = ephy_file_tmp_filename (save_to, "xml");
+ g_free (save_to);
+ save_to = tmp;
+ }
+ else
+ {
+ save_to = g_strdup (filename);
+ }
+
+ return save_to;
+}
+
+static void
+do_session_resume (Session *session)
+{
+ const char *crashed_session;
+
+ crashed_session = get_session_filename (SESSION_CRASHED);
+ session_load (session, crashed_session);
+}
+
+static void
+crashed_resume_dialog (Session *session)
+{
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *image;
+
+ dialog = gtk_dialog_new_with_buttons
+ (_("Crash Recovery"), NULL,
+ GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("_Recover"), GTK_RESPONSE_OK,
+ NULL);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
+ TRUE, TRUE, 0);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (hbox), image,
+ TRUE, TRUE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox,
+ TRUE, TRUE, 0);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_widget_show (label);
+ gtk_label_set_markup (GTK_LABEL (label),
+ _("<b>Epiphany appears to have crashed or been killed the last time it was run.</b>"));
+ gtk_box_pack_start (GTK_BOX (vbox), label,
+ TRUE, TRUE, 0);
+
+ label = gtk_label_new (_("You can recover the opened tabs and windows."));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (vbox), label,
+ TRUE, TRUE, 0);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
+ {
+ do_session_resume (session);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+/**
+ * session_autoresume:
+ * @session: a #Session
+ *
+ * Resume a crashed session when necessary (interactive)
+ *
+ * Return value: return false if no window has been opened
+ **/
+gboolean
+session_autoresume (Session *session)
+{
+ char *saved_session;
+ gboolean loaded = FALSE;
+
+ saved_session = get_session_filename (SESSION_CRASHED);
+
+ if (g_file_test (saved_session, G_FILE_TEST_EXISTS))
+ {
+ crashed_resume_dialog (session);
+ loaded = TRUE;
+ }
+
+ g_free (saved_session);
+
+ /* return false if no window has been opened */
+ return (session->priv->windows != NULL);
+}
+
+static void
+create_session_directory (void)
+{
+ char *dir;
+
+ dir = g_build_filename (ephy_dot_dir (),
+ "/sessions",
+ NULL);
+
+ if (!g_file_test (dir, G_FILE_TEST_EXISTS))
+ {
+ if (mkdir (dir, 488) != 0)
+ {
+ g_error ("couldn't make %s' directory", dir);
+ }
+ }
+
+ g_free (dir);
+}
+
+static gboolean
+save_yourself_cb (GnomeClient *client,
+ gint phase,
+ GnomeSaveStyle save_style,
+ gboolean shutdown,
+ GnomeInteractStyle interact_style,
+ gboolean fast,
+ Session *session)
+{
+ char *argv[] = { "ephy", "--load-session", NULL };
+ char *discard_argv[] = { "rm", "-r", NULL };
+
+ argv[2] = get_session_filename (SESSION_GNOME);
+ gnome_client_set_restart_command
+ (client, 3, argv);
+
+ discard_argv[2] = argv[2];
+ gnome_client_set_discard_command (client, 3,
+ discard_argv);
+
+ session_save (session, argv[2]);
+
+ g_free (argv[2]);
+
+ return TRUE;
+}
+
+static void
+session_die_cb (GnomeClient* client,
+ Session *session)
+{
+ session_close (session);
+}
+
+static void
+gnome_session_init (Session *session)
+{
+ GnomeClient *client;
+
+ client = gnome_master_client ();
+
+ g_signal_connect (G_OBJECT (client),
+ "save_yourself",
+ G_CALLBACK (save_yourself_cb),
+ session);
+
+ g_signal_connect (G_OBJECT (client),
+ "die",
+ G_CALLBACK (session_die_cb),
+ session);
+}
+
+static void
+session_init (Session *session)
+{
+ session->priv = g_new0 (SessionPrivate, 1);
+ session->priv->windows = NULL;
+ session->priv->dont_remove_crashed = FALSE;
+
+ create_session_directory ();
+
+ gnome_session_init (session);
+}
+
+/*
+ * session_close:
+ * @session: a #Session
+ *
+ * Close the session and all the owned windows
+ **/
+void
+session_close (Session *session)
+{
+ GList *l;
+
+ /* close all windows */
+ l = g_list_copy (session->priv->windows);
+ for (; l != NULL; l = l->next)
+ {
+ EphyWindow *window = EPHY_WINDOW(l->data);
+ gtk_widget_destroy (GTK_WIDGET(window));
+ }
+}
+
+static void
+session_delete (Session *session,
+ const char *filename)
+{
+ char *save_to;
+
+ save_to = get_session_filename (filename);
+
+ gnome_vfs_unlink (save_to);
+
+ g_free (save_to);
+}
+
+static void
+session_dispose (GObject *object)
+{
+ Session *session = SESSION(object);
+
+ if (!session->priv->dont_remove_crashed)
+ {
+ session_delete (session, SESSION_CRASHED);
+ }
+}
+
+static void
+session_finalize (GObject *object)
+{
+ Session *t;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_SESSION (object));
+
+ t = SESSION (object);
+
+ g_return_if_fail (t->priv != NULL);
+
+ g_list_free (t->priv->windows);
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * session_new:
+ *
+ * Create a #Session. A session hold the information
+ * about the windows currently opened and is able to persist
+ * and restore his status.
+ **/
+Session *
+session_new (void)
+{
+ Session *t;
+
+ t = SESSION (g_object_new (SESSION_TYPE, NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+static void
+save_tab (EphyWindow *window,
+ EphyTab *tab,
+ xmlDocPtr doc,
+ xmlNodePtr window_node)
+{
+ EmbedChromeMask chrome;
+ const char *location;
+ const char *title;
+ xmlNodePtr embed_node;
+
+ chrome = ephy_window_get_chrome (window);
+
+ /* skip if it's a XUL dialog */
+ if (chrome & EMBED_CHROME_OPENASCHROME) return;
+
+ /* make a new XML node */
+ embed_node = xmlNewDocNode (doc, NULL,
+ "embed", NULL);
+
+ /* store title in the node */
+ title = ephy_tab_get_title (tab);
+ xmlSetProp (embed_node, "title", title);
+
+ /* otherwise, use the actual location. */
+ location = ephy_tab_get_location (tab);
+ xmlSetProp (embed_node, "url", location);
+
+ /* insert node into the tree */
+ xmlAddChild (window_node, embed_node);
+}
+
+/*
+ * session_save:
+ * @session: a #Session
+ * @filename: path of the xml file where the session is saved.
+ *
+ * Save the session on disk. Keep information about window size,
+ * opened urls ...
+ **/
+void
+session_save (Session *session,
+ const char *filename)
+{
+ GList *w;
+ xmlNodePtr root_node;
+ xmlNodePtr window_node;
+ xmlDocPtr doc;
+ gchar buffer[32];
+ char *save_to;
+
+ save_to = get_session_filename (filename);
+
+ doc = xmlNewDoc ("1.0");
+
+ /* create and set the root node for the session */
+ root_node = xmlNewDocNode (doc, NULL, "session", NULL);
+ xmlDocSetRootElement (doc, root_node);
+
+ w = session_get_windows (session);
+
+ /* iterate through all the windows */
+ for (; w != NULL; w = w->next)
+ {
+ const GList *tabs;
+ int x = 0, y = 0, width = 0, height = 0;
+ EphyWindow *window = EPHY_WINDOW(w->data);
+ GtkWidget *wmain;
+
+ tabs = ephy_window_get_tabs (window);
+ g_return_if_fail (tabs != NULL);
+
+ /* make a new XML node */
+ window_node = xmlNewDocNode (doc, NULL, "window", NULL);
+
+ /* get window geometry */
+ wmain = GTK_WIDGET (window);
+ gtk_window_get_size (GTK_WINDOW(wmain), &width, &height);
+ gtk_window_get_position (GTK_WINDOW(wmain), &x, &y);
+
+ /* set window properties */
+ snprintf(buffer, 32, "%d", x);
+ xmlSetProp (window_node, "x", buffer);
+ snprintf(buffer, 32, "%d", y);
+
+ xmlSetProp (window_node, "y", buffer);
+ snprintf(buffer, 32, "%d", width);
+ xmlSetProp (window_node, "width", buffer);
+ snprintf(buffer, 32, "%d", height);
+ xmlSetProp (window_node, "height", buffer);
+
+ for (; tabs != NULL; tabs = tabs->next)
+ {
+ EphyTab *tab = EPHY_TAB(tabs->data);
+ save_tab (window, tab, doc, window_node);
+ }
+
+ xmlAddChild (root_node, window_node);
+ }
+
+ /* save it all out to disk */
+ xmlSaveFile (save_to, doc);
+ xmlFreeDoc (doc);
+
+ g_free (save_to);
+}
+
+static void
+parse_embed (xmlNodePtr child, EphyWindow *window)
+{
+ EphyTab *tab;
+ EphyEmbed *embed;
+
+ while (child != NULL)
+ {
+ if (strcmp (child->name, "embed") == 0)
+ {
+ char *url;
+ char *title;
+
+ g_return_if_fail (window != NULL);
+
+ url = xmlGetProp (child, "url");
+ title = xmlGetProp (child, "title");
+
+ tab = ephy_tab_new ();
+ embed = ephy_tab_get_embed (tab);
+
+ gtk_widget_show (GTK_WIDGET(embed));
+
+ ephy_window_add_tab (window, tab, FALSE);
+
+ ephy_embed_load_url (embed, url);
+
+ xmlFree (url);
+ xmlFree (title);
+ }
+
+ child = child->next;
+ }
+}
+
+/*
+ * session_load:
+ * @session: a #Session
+ * @filename: the path of the source file
+ *
+ * Load a session from disk, restoring the windows and their state
+ **/
+void
+session_load (Session *session,
+ const char *filename)
+{
+ xmlDocPtr doc;
+ xmlNodePtr child;
+ GtkWidget *wmain;
+ EphyWindow *window;
+ char *save_to;
+
+ save_to = get_session_filename (filename);
+
+ doc = xmlParseFile (save_to);
+
+ child = xmlDocGetRootElement (doc);
+
+ /* skip the session node */
+ child = child->children;
+
+ while (child != NULL)
+ {
+ if (strcmp (child->name, "window") == 0)
+ {
+ gint x = 0, y = 0, width = 0, height = 0;
+ xmlChar *tmp;
+
+ tmp = xmlGetProp (child, "x");
+ ephy_str_to_int (tmp, &x);
+ xmlFree (tmp);
+ tmp = xmlGetProp (child, "y");
+ ephy_str_to_int (tmp, &y);
+ xmlFree (tmp);
+ tmp = xmlGetProp (child, "width");
+ ephy_str_to_int (tmp, &width);
+ xmlFree (tmp);
+ tmp = xmlGetProp (child, "height");
+ ephy_str_to_int (tmp, &height);
+ xmlFree (tmp);
+
+ window = ephy_window_new ();
+ wmain = GTK_WIDGET (window);
+ gtk_widget_show (GTK_WIDGET(window));
+
+ gtk_window_move (GTK_WINDOW(wmain), x, y);
+ gtk_window_set_default_size (GTK_WINDOW (wmain),
+ width, height);
+
+ parse_embed (child->children, window);
+ }
+
+ child = child->next;
+ }
+
+ xmlFreeDoc (doc);
+
+ g_free (save_to);
+}
+
+GList *
+session_get_windows (Session *session)
+{
+ g_return_val_if_fail (IS_SESSION (session), NULL);
+
+ return session->priv->windows;
+}
+
+/**
+ * session_add_window:
+ * @session: a #Session
+ * @window: a #EphyWindow
+ *
+ * Add a window to the session. #EphyWindow take care of adding
+ * itself to session.
+ **/
+void
+session_add_window (Session *session,
+ EphyWindow *window)
+{
+ session->priv->windows = g_list_append (session->priv->windows, window);
+
+ g_signal_emit (G_OBJECT (session),
+ session_signals[NEW_WINDOW],
+ 0, window);
+}
+
+/**
+ * session_remove_window:
+ * @session: a #Session
+ * @window: a #EphyWindow
+ *
+ * Remove a window from the session. #EphyWindow take care of removing
+ * itself to session.
+ **/
+void
+session_remove_window (Session *session,
+ EphyWindow *window)
+{
+ g_signal_emit (G_OBJECT (session),
+ session_signals[CLOSE_WINDOW],
+ 0);
+
+ session->priv->windows = g_list_remove (session->priv->windows, window);
+
+ /* autodestroy of the session, necessay to avoid
+ * conflicts with the nautilus view */
+ if (session->priv->windows == NULL)
+ {
+ g_object_unref (session);
+ }
+}
+
diff --git a/src/session.h b/src/session.h
new file mode 100644
index 000000000..e2ac6b9b2
--- /dev/null
+++ b/src/session.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SESSION_H
+#define SESSION_H
+
+#define SESSION_CRASHED "type:session_crashed"
+#define SESSION_GNOME "type:session_gnome"
+
+#include "ephy-window.h"
+
+G_BEGIN_DECLS
+
+#include <glib-object.h>
+#include <glib.h>
+
+typedef struct Session Session;
+typedef struct SessionClass SessionClass;
+
+#define SESSION_TYPE (session_get_type ())
+#define SESSION(obj) (GTK_CHECK_CAST ((obj), SESSION_TYPE, Session))
+#define SESSION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SESSION, SessionClass))
+#define IS_SESSION(obj) (GTK_CHECK_TYPE ((obj), SESSION_TYPE))
+#define IS_SESSION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SESSION))
+
+typedef struct SessionPrivate SessionPrivate;
+
+struct Session
+{
+ GObject parent;
+ SessionPrivate *priv;
+};
+
+struct SessionClass
+{
+ GObjectClass parent_class;
+
+ void ( *new_window) (Session *session,
+ EphyWindow *window);
+ void ( *close_window) (Session *session);
+};
+
+GType session_get_type (void);
+
+Session *session_new (void);
+
+void session_close (Session *session);
+
+void session_load (Session *session,
+ const char *filename);
+
+void session_save (Session *session,
+ const char *filename);
+
+gboolean session_autoresume (Session *session);
+
+GList *session_get_windows (Session *session);
+
+void session_add_window (Session *session,
+ EphyWindow *window);
+
+void session_remove_window (Session *session,
+ EphyWindow *window);
+
+EphyWindow *session_get_active_window (Session *session);
+
+G_END_DECLS
+
+#endif
diff --git a/src/statusbar.c b/src/statusbar.c
new file mode 100755
index 000000000..8ac84cfb9
--- /dev/null
+++ b/src/statusbar.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "statusbar.h"
+#include "ephy-stock-icons.h"
+#include "ephy-bonobo-extensions.h"
+
+#include <string.h>
+#include <time.h>
+#include <gtk/gtkprogressbar.h>
+#include <gtk/gtkeventbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtktooltips.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-control.h>
+
+static void statusbar_class_init (StatusbarClass *klass);
+static void statusbar_init (Statusbar *t);
+static void statusbar_finalize (GObject *object);
+static void
+statusbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+statusbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void
+statusbar_set_window (Statusbar *t, EphyWindow *window);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+static GObjectClass *parent_class = NULL;
+
+struct StatusbarPrivate
+{
+ EphyWindow *window;
+ BonoboUIComponent *ui_component;
+ GtkWidget *security_icon;
+ GtkWidget *progress;
+ GtkTooltips *tooltips;
+ GtkWidget *security_evbox;
+ gboolean visibility;
+};
+
+GType
+statusbar_get_type (void)
+{
+ static GType statusbar_type = 0;
+
+ if (statusbar_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (StatusbarClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) statusbar_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (Statusbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) statusbar_init
+ };
+
+ statusbar_type = g_type_register_static (G_TYPE_OBJECT,
+ "Statusbar",
+ &our_info, 0);
+ }
+
+ return statusbar_type;
+
+}
+
+static void
+statusbar_class_init (StatusbarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = statusbar_finalize;
+ object_class->set_property = statusbar_set_property;
+ object_class->get_property = statusbar_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+statusbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Statusbar *s = STATUSBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ statusbar_set_window (s, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+statusbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Statusbar *s = STATUSBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, s->priv->window);
+ break;
+ }
+}
+
+static void
+create_statusbar_security_icon (Statusbar *s)
+{
+ GtkWidget *security_frame;
+ BonoboControl *control;
+
+ security_frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (security_frame),
+ GTK_SHADOW_IN);
+
+ s->priv->security_icon = gtk_image_new ();
+ s->priv->security_evbox = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER (security_frame),
+ GTK_WIDGET (s->priv->security_evbox));
+ gtk_container_add (GTK_CONTAINER (s->priv->security_evbox),
+ GTK_WIDGET (s->priv->security_icon));
+ /*
+ g_signal_connect (G_OBJECT (security_eventbox),
+ "button_release_event",
+ GTK_SIGNAL_FUNC
+ (security_icon_button_release_cb), t);
+ */
+
+ control = bonobo_control_new (security_frame);
+ bonobo_ui_component_object_set (s->priv->ui_component,
+ "/status/SecurityIconWrapper",
+ BONOBO_OBJREF (control),
+ NULL);
+ bonobo_object_unref (control);
+
+ statusbar_set_security_state (s, FALSE, NULL);
+
+ gtk_widget_show_all (security_frame);
+}
+
+static void
+create_statusbar_progress (Statusbar *s)
+{
+ BonoboControl *control;
+
+ s->priv->progress = gtk_progress_bar_new ();
+
+ control = bonobo_control_new (s->priv->progress);
+ bonobo_ui_component_object_set (s->priv->ui_component,
+ "/status/ProgressWrapper",
+ BONOBO_OBJREF (control),
+ NULL);
+
+ gtk_widget_show_all (s->priv->progress);
+}
+
+static void
+statusbar_set_window (Statusbar *s, EphyWindow *window)
+{
+ g_return_if_fail (s->priv->window == NULL);
+
+ s->priv->window = window;
+ s->priv->ui_component = BONOBO_UI_COMPONENT
+ (s->priv->window->ui_component);
+
+ create_statusbar_progress (s);
+ create_statusbar_security_icon (s);
+}
+
+static void
+statusbar_init (Statusbar *t)
+{
+ t->priv = g_new0 (StatusbarPrivate, 1);
+ t->priv->visibility = TRUE;
+
+ t->priv->tooltips = gtk_tooltips_new ();
+}
+
+static void
+statusbar_finalize (GObject *object)
+{
+ Statusbar *t;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_STATUSBAR (object));
+
+ t = STATUSBAR (object);
+
+ g_return_if_fail (t->priv != NULL);
+
+ gtk_object_destroy (GTK_OBJECT (t->priv->tooltips));
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+Statusbar *
+statusbar_new (EphyWindow *window)
+{
+ Statusbar *t;
+
+ t = STATUSBAR (g_object_new (STATUSBAR_TYPE,
+ "EphyWindow", window,
+ NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+void
+statusbar_set_visibility (Statusbar *t,
+ gboolean visibility)
+{
+ if (visibility == t->priv->visibility) return;
+
+ t->priv->visibility = visibility;
+
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component),
+ "/status",
+ !visibility);
+}
+
+void
+statusbar_set_security_state (Statusbar *t,
+ gboolean state,
+ const char *tooltip)
+{
+ const char *stock;
+
+ stock = state ? EPHY_STOCK_SECURE : EPHY_STOCK_UNSECURE;
+
+ gtk_image_set_from_stock (GTK_IMAGE (t->priv->security_icon), stock,
+ GTK_ICON_SIZE_MENU);
+
+ gtk_tooltips_set_tip (t->priv->tooltips, t->priv->security_evbox,
+ tooltip, NULL);
+}
+
+void
+statusbar_set_progress (Statusbar *t,
+ int progress)
+{
+ if (progress == -1)
+ {
+ gtk_progress_bar_pulse (GTK_PROGRESS_BAR(t->priv->progress));
+ }
+ else
+ {
+ float tmp;
+ tmp = (float)(progress) / 100;
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(t->priv->progress),
+ tmp);
+ }
+}
+
+void
+statusbar_set_message (Statusbar *s,
+ const char *message)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT(s->priv->ui_component));
+ g_return_if_fail (message != NULL);
+
+ /* Bonobo doesnt like 0 length messages */
+ if (g_utf8_strlen (message, -1) == 0)
+ {
+ message = " ";
+ }
+
+ if (bonobo_ui_component_get_container (s->priv->ui_component)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_status (s->priv->ui_component,
+ message,
+ NULL);
+ }
+}
+
diff --git a/src/statusbar.h b/src/statusbar.h
new file mode 100644
index 000000000..590b89394
--- /dev/null
+++ b/src/statusbar.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef STATUSBAR_H
+#define STATUSBAR_H
+
+#include "ephy-window.h"
+
+G_BEGIN_DECLS
+
+#include <glib-object.h>
+#include <glib.h>
+
+typedef struct Statusbar Statusbar;
+typedef struct StatusbarClass StatusbarClass;
+
+#define STATUSBAR_TYPE (statusbar_get_type ())
+#define STATUSBAR(obj) (GTK_CHECK_CAST ((obj), STATUSBAR_TYPE, Statusbar))
+#define STATUSBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), STATUSBAR, StatusbarClass))
+#define IS_STATUSBAR(obj) (GTK_CHECK_TYPE ((obj), STATUSBAR_TYPE))
+#define IS_STATUSBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), STATUSBAR))
+
+typedef struct StatusbarPrivate StatusbarPrivate;
+
+struct Statusbar
+{
+ GObject parent;
+ StatusbarPrivate *priv;
+};
+
+struct StatusbarClass
+{
+ GObjectClass parent_class;
+};
+
+GType statusbar_get_type (void);
+
+Statusbar *statusbar_new (EphyWindow *window);
+
+void statusbar_set_visibility (Statusbar *s,
+ gboolean visibility);
+
+void statusbar_set_security_state (Statusbar *s,
+ gboolean state,
+ const char *tooltip);
+
+void statusbar_set_progress (Statusbar *s,
+ int progress);
+
+void statusbar_set_message (Statusbar *s,
+ const gchar *message);
+
+G_END_DECLS
+
+#endif
diff --git a/src/toolbar.c b/src/toolbar.c
new file mode 100755
index 000000000..4bff4615e
--- /dev/null
+++ b/src/toolbar.c
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ * (C) 2001, 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+#include "toolbar.h"
+#include "ephy-spinner.h"
+#include "ephy-window.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+#include "ephy-location-entry.h"
+#include "ephy-shell.h"
+#include "ephy-embed-favicon.h"
+#include "ephy-dnd.h"
+#include "ephy-toolbar-bonobo-view.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include <string.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-ui-toolbar-button-item.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkmenu.h>
+
+#define DEFAULT_TOOLBAR_SETUP \
+ "back=std_toolitem(item=back);" \
+ "back_history=navigation_history(direction=back);" \
+ "up=std_toolitem(item=up);" \
+ "up_history=navigation_history(direction=up);" \
+ "forward=std_toolitem(item=forward);" \
+ "forward_history=navigation_history(direction=forward);" \
+ "stop=std_toolitem(item=stop);" \
+ "reload=std_toolitem(item=reload);" \
+ "home=std_toolitem(item=home);" \
+ "favicon=favicon;" \
+ "location=location;" \
+ "zoom=zoom;" \
+ "spinner=spinner;"
+
+#define ZOOM_DELAY 50
+
+static void toolbar_class_init (ToolbarClass *klass);
+static void toolbar_init (Toolbar *t);
+static void toolbar_finalize (GObject *object);
+static void toolbar_set_window (Toolbar *t, EphyWindow *window);
+static void toolbar_get_widgets (Toolbar *t);
+static void toolbar_changed_cb (EphyToolbar *gt, Toolbar *t);
+static void
+toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+enum
+{
+ TOOLBAR_ITEM_STYLE_PROP,
+ TOOLBAR_ITEM_ORIENTATION_PROP,
+ TOOLBAR_ITEM_PRIORITY_PROP
+};
+
+static GObjectClass *parent_class = NULL;
+
+struct ToolbarPrivate
+{
+ EphyWindow *window;
+ BonoboUIComponent *ui_component;
+ EphyTbBonoboView *bview;
+
+ GtkWidget *spinner;
+ gboolean visibility;
+ /* This field is unused... what is it?
+ GdkPixbufAnimation *animation;
+ */
+ GtkWidget *back_button;
+ GtkWidget *forward_button;
+ GtkWidget *up_button;
+ GtkWidget *location_entry;
+ GtkTooltips *tooltips;
+ GtkWidget *favicon;
+ GtkWidget *favicon_ebox;
+ GtkWidget *zoom_spinbutton;
+ guint zoom_timeout_id;
+ gboolean zoom_lock;
+};
+
+GType
+toolbar_get_type (void)
+{
+ static GType toolbar_type = 0;
+
+ if (toolbar_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (ToolbarClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) toolbar_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (Toolbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) toolbar_init
+ };
+
+ toolbar_type = g_type_register_static (EPHY_TYPE_TOOLBAR,
+ "Toolbar",
+ &our_info, 0);
+ }
+
+ return toolbar_type;
+
+}
+
+static void
+toolbar_class_init (ToolbarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = toolbar_finalize;
+
+ object_class->set_property = toolbar_set_property;
+ object_class->get_property = toolbar_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Toolbar *t = TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ toolbar_set_window (t, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Toolbar *t = TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, t->priv->window);
+ break;
+ }
+}
+
+static GtkWidget *
+new_history_menu_item (gint num, gchar *origtext, gboolean lettersok,
+ GtkWidget *menu, const GdkPixbuf *ico)
+{
+ GtkWidget *item = gtk_image_menu_item_new ();
+ GtkWidget *hb = gtk_hbox_new (FALSE, 0);
+ GtkWidget *label = gtk_label_new (origtext);
+
+ gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (item), hb);
+
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+ gtk_image_new_from_pixbuf ((GdkPixbuf *) ico));
+
+ gtk_widget_show_all (item);
+
+ return item;
+}
+
+static void
+activate_back_or_forward_menu_item_cb (GtkWidget *menu, EphyWindow *window)
+{
+ EphyEmbed *embed;
+ int go_nth;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth");
+
+ ephy_embed_shistory_go_nth (embed, go_nth);
+}
+
+static void
+activate_up_menu_item_cb (GtkWidget *menu, EphyWindow *window)
+{
+ EphyEmbed *embed;
+ int go_nth;
+ GSList *l;
+ gchar *url;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth");
+
+ ephy_embed_get_go_up_list (embed, &l);
+
+ url = g_slist_nth_data (l, go_nth);
+ if (url)
+ {
+ ephy_embed_load_url (embed, url);
+ }
+
+ g_slist_foreach (l, (GFunc) g_free, NULL);
+ g_slist_free (l);
+}
+
+static gboolean
+back_or_forward_button_pressed_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer *user_data)
+{
+ Toolbar *t;
+ GtkWidget *menu;
+ int pos, count;
+ EphyEmbed *embed;
+ int start, end, accell_count = 0;
+
+ g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
+
+ t = TOOLBAR (user_data);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+ embed = ephy_window_get_active_embed (t->priv->window);
+ g_return_val_if_fail (embed != NULL, FALSE);
+
+ ephy_embed_shistory_get_pos (embed, &pos);
+ ephy_embed_shistory_count (embed, &count);
+
+ if (count == 0) return FALSE;
+
+ if (widget == t->priv->back_button)
+ {
+ start = pos - 1;
+ end = -1;
+ }
+ else
+ {
+ start = pos + 1;
+ end = count;
+ }
+
+ menu = gtk_menu_new ();
+
+ while (start != end)
+ {
+ char *title, *url;
+ GtkWidget *item;
+ ephy_embed_shistory_get_nth (embed, start, FALSE,
+ &url, &title);
+ item = new_history_menu_item (accell_count, url, TRUE,
+ menu, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (start));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (activate_back_or_forward_menu_item_cb),
+ t->priv->window);
+ gtk_widget_show_all (item);
+
+ g_free (url);
+ g_free (title);
+
+ accell_count++;
+ if (start < end) start++;
+ else start--;
+ }
+
+
+ gnome_popup_menu_do_popup_modal (menu,
+ ephy_gui_menu_position_under_widget, widget, event, widget, widget);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+ return TRUE;
+}
+
+static gboolean
+up_button_pressed_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer *user_data)
+{
+ Toolbar *t;
+ GtkWidget *menu;
+ EphyEmbed *embed;
+ int accell_count = 0;
+ GSList *l;
+ GSList *li;
+
+ g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
+
+ t = TOOLBAR (user_data);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+ embed = ephy_window_get_active_embed (t->priv->window);
+ g_return_val_if_fail (embed != NULL, FALSE);
+
+ ephy_embed_get_go_up_list (embed, &l);
+
+ if (l == NULL) return FALSE;
+
+ menu = gtk_menu_new ();
+
+ for (li = l; li; li = li->next)
+ {
+ char *url = li->data;
+ GtkWidget *item;
+ item = new_history_menu_item (accell_count, url, TRUE,
+ menu, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (accell_count));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (activate_up_menu_item_cb),
+ t->priv->window);
+ gtk_widget_show_all (item);
+
+ accell_count++;
+ }
+
+ g_slist_foreach (l, (GFunc) g_free, NULL);
+ g_slist_free (l);
+
+ gnome_popup_menu_do_popup_modal (menu,
+ ephy_gui_menu_position_under_widget, widget, event, widget, widget);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+ return TRUE;
+}
+
+static gboolean
+back_or_forward_key_pressed_callback (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer *user_data)
+{
+ if (event->keyval == GDK_space ||
+ event->keyval == GDK_KP_Space ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ back_or_forward_button_pressed_callback (widget, NULL, user_data);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+up_key_pressed_callback (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer *user_data)
+{
+ if (event->keyval == GDK_space ||
+ event->keyval == GDK_KP_Space ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ up_button_pressed_callback (widget, NULL, user_data);
+ }
+
+ return FALSE;
+}
+
+static void
+toolbar_setup_navigation_button (Toolbar *t, GtkWidget *w, const char *tooltip)
+{
+ g_signal_connect_object (w, "key_press_event",
+ G_CALLBACK (back_or_forward_key_pressed_callback),
+ t, 0);
+ g_signal_connect_object (w, "button_press_event",
+ G_CALLBACK (back_or_forward_button_pressed_callback),
+ t, 0);
+
+ gtk_tooltips_set_tip (t->priv->tooltips, w, tooltip, NULL);
+}
+
+static void
+toolbar_setup_up_button (Toolbar *t, GtkWidget *w, const char *tooltip)
+{
+ g_signal_connect_object (w, "key_press_event",
+ G_CALLBACK (up_key_pressed_callback),
+ t, 0);
+ g_signal_connect_object (w, "button_press_event",
+ G_CALLBACK (up_button_pressed_callback),
+ t, 0);
+
+ gtk_tooltips_set_tip (t->priv->tooltips, w, tooltip, NULL);
+}
+
+
+static void
+toolbar_location_url_activate_cb (EphyLocationEntry *entry,
+ const char *content,
+ const char *target,
+ EphyWindow *window)
+{
+ EphyBookmarks *bookmarks;
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+
+ if (!content)
+ {
+ ephy_window_load_url (window, target);
+ }
+ else
+ {
+ char *url;
+
+ url = ephy_bookmarks_solve_smart_url
+ (bookmarks, target, content);
+ g_return_if_fail (url != NULL);
+ ephy_window_load_url (window, url);
+ g_free (url);
+ }
+}
+
+static void
+each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee,
+ gpointer iterator_context, gpointer data)
+{
+ const char *location;
+ EphyTab *tab;
+ EphyWindow *window = EPHY_WINDOW(iterator_context);
+
+ tab = ephy_window_get_active_tab (window);
+ location = ephy_tab_get_location (tab);
+
+ iteratee (location, -1, -1, -1, -1, data);
+}
+
+static void
+favicon_drag_data_get_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint32 time,
+ EphyWindow *window)
+{
+ g_assert (widget != NULL);
+ g_return_if_fail (context != NULL);
+
+ ephy_dnd_drag_data_get (widget, context, selection_data,
+ info, time, window, each_url_get_data_binder);
+}
+
+static void
+toolbar_setup_favicon_ebox (Toolbar *t, GtkWidget *w)
+{
+ ToolbarPrivate *p = t->priv;
+
+ g_return_if_fail (w == p->favicon_ebox);
+
+ p->favicon = g_object_ref (ephy_embed_favicon_new
+ (ephy_window_get_active_embed (p->window)));
+ gtk_container_add (GTK_CONTAINER (p->favicon_ebox), p->favicon);
+ gtk_container_set_border_width (GTK_CONTAINER (p->favicon_ebox), 2);
+
+ ephy_dnd_url_drag_source_set (p->favicon_ebox);
+
+ g_signal_connect (G_OBJECT (p->favicon_ebox),
+ "drag_data_get",
+ G_CALLBACK (favicon_drag_data_get_cb),
+ p->window);
+ gtk_widget_show_all (p->favicon_ebox);
+}
+
+static gboolean
+toolbar_zoom_timeout_cb (gpointer data)
+{
+ Toolbar *t = data;
+ gint zoom = toolbar_get_zoom (t);
+
+ g_return_val_if_fail (IS_EPHY_WINDOW (t->priv->window), FALSE);
+
+ ephy_window_set_zoom (t->priv->window, zoom);
+
+ return FALSE;
+}
+
+static void
+toolbar_zoom_spinbutton_value_changed_cb (GtkSpinButton *sb, Toolbar *t)
+{
+ ToolbarPrivate *p = t->priv;
+ if (p->zoom_timeout_id != 0)
+ {
+ g_source_remove (p->zoom_timeout_id);
+ }
+ if (!p->zoom_lock)
+ {
+ p->zoom_timeout_id = g_timeout_add (ZOOM_DELAY, toolbar_zoom_timeout_cb, t);
+ }
+}
+
+static void
+toolbar_setup_zoom_spinbutton (Toolbar *t, GtkWidget *w)
+{
+ g_signal_connect (w, "value_changed",
+ G_CALLBACK (toolbar_zoom_spinbutton_value_changed_cb), t);
+ gtk_tooltips_set_tip (t->priv->tooltips, w, _("Zoom"), NULL);
+}
+
+static void
+toolbar_setup_location_entry (Toolbar *t, GtkWidget *w)
+{
+ EphyAutocompletion *ac = ephy_shell_get_autocompletion (ephy_shell);
+ EphyLocationEntry *e;
+
+ g_return_if_fail (w == t->priv->location_entry);
+ g_return_if_fail (EPHY_IS_LOCATION_ENTRY (w));
+
+ e = EPHY_LOCATION_ENTRY (w);
+ ephy_location_entry_set_autocompletion (e, ac);
+
+ g_signal_connect (e, "activated",
+ GTK_SIGNAL_FUNC(toolbar_location_url_activate_cb),
+ t->priv->window);
+}
+
+static void
+toolbar_setup_spinner (Toolbar *t, GtkWidget *w)
+{
+ ToolbarPrivate *p = t->priv;
+ GtkWidget *spinner;
+
+ g_return_if_fail (w == p->spinner);
+
+ /* build the spinner and insert it into the box */
+ spinner = ephy_spinner_new ();
+ ephy_spinner_set_small_mode (EPHY_SPINNER (spinner), TRUE);
+ gtk_container_add (GTK_CONTAINER (p->spinner), spinner);
+ gtk_widget_show (spinner);
+
+ /* don't care about the box anymore */
+ g_object_unref (p->spinner);
+ p->spinner = g_object_ref (spinner);
+}
+
+
+static void
+toolbar_set_window (Toolbar *t, EphyWindow *window)
+{
+ g_return_if_fail (t->priv->window == NULL);
+
+ t->priv->window = window;
+ t->priv->ui_component = g_object_ref (t->priv->window->ui_component);
+
+ ephy_tb_bonobo_view_set_path (t->priv->bview, t->priv->ui_component, "/Toolbar");
+
+ toolbar_get_widgets (t);
+}
+
+static void
+toolbar_get_widgets (Toolbar *t)
+{
+ ToolbarPrivate *p;
+ EphyToolbar *gt;
+ EphyTbItem *it;
+
+ DEBUG_MSG (("in toolbar_get_widgets\n"));
+
+ g_return_if_fail (IS_TOOLBAR (t));
+ p = t->priv;
+ g_return_if_fail (IS_EPHY_WINDOW (p->window));
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui_component));
+
+ /* release all the widgets */
+
+ if (p->back_button)
+ {
+ g_object_unref (p->back_button);
+ p->back_button = NULL;
+ }
+
+ if (p->forward_button)
+ {
+ g_object_unref (p->forward_button);
+ p->forward_button = NULL;
+ }
+
+ if (p->up_button)
+ {
+ g_object_unref (p->up_button);
+ p->up_button = NULL;
+ }
+
+ if (p->favicon_ebox)
+ {
+ g_object_unref (p->favicon_ebox);
+ p->favicon_ebox = NULL;
+ }
+
+ if (p->favicon)
+ {
+ g_object_unref (p->favicon);
+ p->favicon = NULL;
+ }
+
+ if (p->location_entry)
+ {
+ g_object_unref (p->location_entry);
+ p->location_entry = NULL;
+ }
+
+ if (p->spinner)
+ {
+ g_object_unref (p->spinner);
+ p->spinner = NULL;
+ }
+
+ if (p->zoom_spinbutton)
+ {
+ g_object_unref (p->zoom_spinbutton);
+ p->zoom_spinbutton = NULL;
+ }
+
+ gt = EPHY_TOOLBAR (t);
+
+ it = ephy_toolbar_get_item_by_id (gt, "back_history");
+ if (it)
+ {
+ p->back_button = ephy_tb_item_get_widget (it);
+ g_object_ref (p->back_button);
+ toolbar_setup_navigation_button (t, p->back_button, _("Go back a number of pages"));
+
+ DEBUG_MSG ((" got a back_history button\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "forward_history");
+ if (it)
+ {
+ p->forward_button = ephy_tb_item_get_widget (it);
+ g_object_ref (p->forward_button);
+ toolbar_setup_navigation_button (t, p->forward_button, _("Go forward a number of pages"));
+
+ DEBUG_MSG ((" got a forward_history button\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "up_history");
+ if (it)
+ {
+ p->up_button = ephy_tb_item_get_widget (it);
+ g_object_ref (p->up_button);
+ toolbar_setup_up_button (t, p->up_button, _("Go up a number of levels"));
+
+ DEBUG_MSG ((" got a up_history button\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "location");
+ if (it)
+ {
+ p->location_entry = ephy_tb_item_get_widget (it);
+ g_object_ref (p->location_entry);
+ toolbar_setup_location_entry (t, p->location_entry);
+
+ DEBUG_MSG ((" got a location entry\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "favicon");
+ if (it)
+ {
+ p->favicon_ebox = ephy_tb_item_get_widget (it);
+ g_object_ref (p->favicon_ebox);
+ toolbar_setup_favicon_ebox (t, p->favicon_ebox);
+
+ DEBUG_MSG ((" got a favicon ebox\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "spinner");
+ if (it)
+ {
+ p->spinner = ephy_tb_item_get_widget (it);
+ g_object_ref (p->spinner);
+ toolbar_setup_spinner (t, p->spinner);
+
+ DEBUG_MSG ((" got a spinner\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "zoom");
+ if (it)
+ {
+ p->zoom_spinbutton = ephy_tb_item_get_widget (it);
+ g_object_ref (p->zoom_spinbutton);
+ toolbar_setup_zoom_spinbutton (t, p->zoom_spinbutton);
+
+ DEBUG_MSG ((" got a zoom control\n"));
+ }
+
+ /* update the controls */
+ ephy_window_update_all_controls (p->window);
+}
+
+static void
+toolbar_init (Toolbar *t)
+{
+ t->priv = g_new0 (ToolbarPrivate, 1);
+
+ t->priv->window = NULL;
+ t->priv->ui_component = NULL;
+ t->priv->visibility = TRUE;
+ t->priv->tooltips = gtk_tooltips_new ();
+ g_object_ref (t->priv->tooltips);
+ gtk_object_sink (GTK_OBJECT (t->priv->tooltips));
+
+ if (!ephy_toolbar_listen_to_gconf (EPHY_TOOLBAR (t), CONF_TOOLBAR_SETUP))
+ {
+ /* FIXME: make this a dialog? */
+ g_warning ("An incorrect toolbar configuration has been found, resetting to the default");
+
+ /* this is to make sure we get a toolbar, even if the
+ setup is wrong or there is no schema */
+ eel_gconf_set_string (CONF_TOOLBAR_SETUP, DEFAULT_TOOLBAR_SETUP);
+ }
+
+ g_signal_connect (t, "changed", G_CALLBACK (toolbar_changed_cb), t);
+
+ t->priv->bview = ephy_tb_bonobo_view_new ();
+ ephy_tb_bonobo_view_set_toolbar (t->priv->bview, EPHY_TOOLBAR (t));
+}
+
+static void
+toolbar_changed_cb (EphyToolbar *gt, Toolbar *t)
+{
+ g_return_if_fail (gt == EPHY_TOOLBAR (t));
+
+ if (t->priv->window)
+ {
+ toolbar_get_widgets (t);
+ }
+}
+
+static void
+toolbar_finalize (GObject *object)
+{
+ Toolbar *t;
+ ToolbarPrivate *p;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_TOOLBAR (object));
+
+ t = TOOLBAR (object);
+ p = t->priv;
+
+ g_return_if_fail (p != NULL);
+
+ if (p->location_entry) g_object_unref (p->location_entry);
+ if (p->back_button) g_object_unref (p->back_button);
+ if (p->forward_button) g_object_unref (p->forward_button);
+ if (p->up_button) g_object_unref (p->up_button);
+ if (p->favicon_ebox) g_object_unref (p->favicon_ebox);
+ if (p->favicon) g_object_unref (p->favicon);
+ if (p->spinner) g_object_unref (p->spinner);
+ if (p->tooltips) g_object_unref (p->tooltips);
+ if (p->zoom_spinbutton) g_object_unref (p->zoom_spinbutton);
+ if (p->zoom_timeout_id != 0)
+ {
+ g_source_remove (p->zoom_timeout_id);
+ }
+
+ g_object_unref (t->priv->bview);
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+Toolbar *
+toolbar_new (EphyWindow *window)
+{
+ Toolbar *t;
+
+ t = TOOLBAR (g_object_new (TOOLBAR_TYPE,
+ "EphyWindow", window,
+ NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+void
+toolbar_set_visibility (Toolbar *t, gboolean visibility)
+{
+ if (visibility == t->priv->visibility) return;
+
+ t->priv->visibility = visibility;
+
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component),
+ "/Toolbar",
+ !visibility);
+}
+
+void
+toolbar_activate_location (Toolbar *t)
+{
+ if (t->priv->location_entry)
+ {
+ ephy_location_entry_activate
+ (EPHY_LOCATION_ENTRY(t->priv->location_entry));
+ }
+}
+
+void
+toolbar_spinner_start (Toolbar *t)
+{
+ if (t->priv->spinner)
+ {
+ ephy_spinner_start (EPHY_SPINNER(t->priv->spinner));
+ }
+}
+
+void
+toolbar_spinner_stop (Toolbar *t)
+{
+ if (t->priv->spinner)
+ {
+ ephy_spinner_stop (EPHY_SPINNER(t->priv->spinner));
+ }
+}
+
+void
+toolbar_button_set_sensitive (Toolbar *t,
+ ToolbarButtonID id,
+ gboolean sensitivity)
+{
+ switch (id)
+ {
+ case TOOLBAR_BACK_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoBack",
+ sensitivity);
+ if (t->priv->back_button)
+ {
+ gtk_widget_set_sensitive (t->priv->back_button,
+ sensitivity);
+ }
+ break;
+ case TOOLBAR_FORWARD_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoForward",
+ sensitivity);
+ if (t->priv->forward_button)
+ {
+ gtk_widget_set_sensitive (t->priv->forward_button,
+ sensitivity);
+ }
+ break;
+ case TOOLBAR_STOP_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoStop",
+ sensitivity);
+ break;
+ case TOOLBAR_UP_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoUp",
+ sensitivity);
+ if (t->priv->up_button)
+ {
+ gtk_widget_set_sensitive (t->priv->up_button,
+ sensitivity);
+ }
+ break;
+ }
+}
+
+void
+toolbar_set_location (Toolbar *t,
+ const char *location)
+{
+ g_return_if_fail (location != NULL);
+
+ if (t->priv->location_entry)
+ {
+ ephy_location_entry_set_location
+ (EPHY_LOCATION_ENTRY (t->priv->location_entry), location);
+ }
+}
+
+void
+toolbar_update_favicon (Toolbar *t)
+{
+ if (t->priv->favicon)
+ {
+ ephy_embed_favicon_set_embed (EPHY_EMBED_FAVICON (t->priv->favicon),
+ ephy_window_get_active_embed (t->priv->window));
+ }
+}
+
+char *
+toolbar_get_location (Toolbar *t)
+{
+ gchar *location;
+ if (t->priv->location_entry)
+ {
+ location = ephy_location_entry_get_location
+ (EPHY_LOCATION_ENTRY (t->priv->location_entry));
+ }
+ else
+ {
+ location = g_strdup ("");
+ }
+ return location;
+}
+
+gint
+toolbar_get_zoom (Toolbar *t)
+{
+ gint zoom;
+ if (t->priv->zoom_spinbutton)
+ {
+ zoom = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (t->priv->zoom_spinbutton));
+ }
+ else
+ {
+ zoom = 100;
+ }
+ return zoom;
+}
+
+void
+toolbar_set_zoom (Toolbar *t, gint zoom)
+{
+ ToolbarPrivate *p = t->priv;
+ if (p->zoom_spinbutton)
+ {
+ p->zoom_lock = TRUE;
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (p->zoom_spinbutton), zoom);
+ p->zoom_lock = FALSE;
+ }
+}
+
diff --git a/src/toolbar.h b/src/toolbar.h
new file mode 100644
index 000000000..5764c14e1
--- /dev/null
+++ b/src/toolbar.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TOOLBAR_H
+#define TOOLBAR_H
+
+#include "ephy-window.h"
+#include <glib-object.h>
+#include <glib.h>
+#include "ephy-toolbar.h"
+
+G_BEGIN_DECLS
+
+typedef struct ToolbarClass ToolbarClass;
+
+#define TOOLBAR_TYPE (toolbar_get_type ())
+#define TOOLBAR(obj) (GTK_CHECK_CAST ((obj), TOOLBAR_TYPE, Toolbar))
+#define TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TOOLBAR, ToolbarClass))
+#define IS_TOOLBAR(obj) (GTK_CHECK_TYPE ((obj), TOOLBAR_TYPE))
+#define IS_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), TOOLBAR))
+
+typedef struct ToolbarPrivate ToolbarPrivate;
+
+typedef enum
+{
+ TOOLBAR_BACK_BUTTON,
+ TOOLBAR_FORWARD_BUTTON,
+ TOOLBAR_STOP_BUTTON,
+ TOOLBAR_UP_BUTTON
+} ToolbarButtonID;
+
+struct Toolbar
+{
+ EphyToolbar parent_object;
+ ToolbarPrivate *priv;
+};
+
+struct ToolbarClass
+{
+ EphyToolbarClass parent_class;
+};
+
+GType toolbar_get_type (void);
+
+Toolbar *toolbar_new (EphyWindow *window);
+
+void toolbar_set_visibility (Toolbar *t,
+ gboolean visibility);
+
+void toolbar_button_set_sensitive (Toolbar *t,
+ ToolbarButtonID id,
+ gboolean sensitivity);
+
+void toolbar_spinner_start (Toolbar *t);
+
+void toolbar_spinner_stop (Toolbar *t);
+
+char *toolbar_get_location (Toolbar *t);
+
+void toolbar_set_location (Toolbar *t,
+ const char *location);
+
+gint toolbar_get_zoom (Toolbar *t);
+
+void toolbar_set_zoom (Toolbar *t, gint zoom);
+
+void toolbar_activate_location (Toolbar *t);
+
+void toolbar_update_favicon (Toolbar *t);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ui-prefs.c b/src/ui-prefs.c
new file mode 100755
index 000000000..e461bf7e6
--- /dev/null
+++ b/src/ui-prefs.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ui-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-spinner.h"
+
+#include <string.h>
+#include <libgnome/gnome-util.h>
+#include <libgnomeui/gnome-icon-list.h>
+
+static void ui_prefs_class_init (UIPrefsClass *klass);
+static void ui_prefs_init (UIPrefs *dialog);
+static void ui_prefs_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+spinners_iconlist_select_icon_cb (GtkWidget *iconlist, gint num,
+ GdkEvent *event, UIPrefs *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct UIPrefsPrivate
+{
+ gpointer dummy;
+ GList *spinner_list;
+};
+
+enum
+{
+ SPINNERS_PROP,
+ OPEN_IN_TABS_PROP,
+ JUMP_TO_PROP,
+ POPUPS_PROP
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { SPINNERS_PROP, "spinners_iconlist", NULL, PT_NORMAL, NULL },
+ { OPEN_IN_TABS_PROP, "open_in_tabs_checkbutton", CONF_TABS_TABBED, PT_AUTOAPPLY, NULL },
+ { JUMP_TO_PROP, "jump_to_checkbutton", CONF_TABS_TABBED_AUTOJUMP, PT_AUTOAPPLY, NULL },
+ { POPUPS_PROP, "popups_checkbutton", CONF_TABS_TABBED_POPUPS, PT_AUTOAPPLY, NULL },
+
+ { -1, NULL, NULL }
+};
+
+GType
+ui_prefs_get_type (void)
+{
+ static GType ui_prefs_type = 0;
+
+ if (ui_prefs_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (UIPrefsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ui_prefs_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (UIPrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ui_prefs_init
+ };
+
+ ui_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "UIPrefs",
+ &our_info, 0);
+ }
+
+ return ui_prefs_type;
+
+}
+
+static void
+ui_prefs_class_init (UIPrefsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ui_prefs_finalize;
+}
+
+/**
+ * Free any existing spinner list.
+ */
+static void
+free_spinner_list (UIPrefs *dialog)
+{
+ GList *node;
+
+ for (node = dialog->priv->spinner_list; node; node = node->next)
+ g_free(node->data);
+
+ g_list_free(dialog->priv->spinner_list);
+ dialog->priv->spinner_list = NULL;
+}
+
+/**
+ * spinner_get_path_from_index: used in prefs_callbacks.c to get the
+ * path of selected icon
+ */
+static const gchar *
+spinner_get_path_from_index (UIPrefs *dialog, gint index)
+{
+ gchar *path;
+
+ path = g_list_nth_data (dialog->priv->spinner_list, index);
+
+ return path;
+}
+
+/*
+ * spinner_fill_iconlist: fill a gnome icon list with icons of available spinners
+ */
+static void
+spinner_fill_iconlist (UIPrefs *dialog, GnomeIconList *icon_list)
+{
+ GList *spinners, *tmp;
+ gchar *pref_spinner_path;
+ gint index;
+
+ /* clear spinner list */
+ free_spinner_list (dialog);
+ gnome_icon_list_clear (GNOME_ICON_LIST (icon_list));
+
+ pref_spinner_path =
+ eel_gconf_get_string (CONF_TOOLBAR_SPINNER_THEME);
+ index = gnome_icon_list_get_num_icons (icon_list);
+
+ spinners = ephy_spinner_list_spinners ();
+ for (tmp = spinners; tmp != NULL; tmp = g_list_next (tmp))
+ {
+ EphySpinnerInfo *info = tmp->data;
+
+ dialog->priv->spinner_list =
+ g_list_append (dialog->priv->spinner_list,
+ g_strdup (info->name));
+
+ gnome_icon_list_append (icon_list, info->filename, info->name);
+
+ /* Select the icon configured in prefs */
+ if (pref_spinner_path &&
+ strcmp (pref_spinner_path, info->name) == 0)
+ {
+ gnome_icon_list_select_icon (icon_list, index);
+ }
+ index++;
+ }
+ g_list_foreach (spinners, (GFunc)ephy_spinner_info_free, NULL);
+ g_list_free (spinners);
+
+ g_free (pref_spinner_path);
+}
+
+static void
+ui_prefs_init (UIPrefs *dialog)
+{
+ GtkWidget *icon_list;
+
+ dialog->priv = g_new0 (UIPrefsPrivate, 1);
+ dialog->priv->spinner_list = NULL;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "prefs-dialog.glade",
+ "ui_page_box");
+
+ icon_list = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ SPINNERS_PROP);
+
+ spinner_fill_iconlist (dialog, GNOME_ICON_LIST (icon_list));
+}
+
+static void
+ui_prefs_finalize (GObject *object)
+{
+ UIPrefs *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_UI_PREFS (object));
+
+ dialog = UI_PREFS (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ free_spinner_list (dialog);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+ui_prefs_new (void)
+{
+ UIPrefs *dialog;
+
+ dialog = UI_PREFS (g_object_new (UI_PREFS_TYPE,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+spinners_iconlist_select_icon_cb (GtkWidget *iconlist, gint num,
+ GdkEvent *event, UIPrefs *dialog)
+{
+ const char *path;
+ path = spinner_get_path_from_index (dialog, num);
+ eel_gconf_set_string (CONF_TOOLBAR_SPINNER_THEME, path);
+}
diff --git a/src/ui-prefs.h b/src/ui-prefs.h
new file mode 100644
index 000000000..bbd3dbe75
--- /dev/null
+++ b/src/ui-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef UI_PREFS_H
+#define UI_PREFS_H
+
+#include "ephy-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct UIPrefs UIPrefs;
+typedef struct UIPrefsClass UIPrefsClass;
+
+#define UI_PREFS_TYPE (ui_prefs_get_type ())
+#define UI_PREFS(obj) (GTK_CHECK_CAST ((obj), UI_PREFS_TYPE, UIPrefs))
+#define UI_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), UI_PREFS, UIPrefsClass))
+#define IS_UI_PREFS(obj) (GTK_CHECK_TYPE ((obj), UI_PREFS_TYPE))
+#define IS_UI_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), UI_PREFS))
+
+typedef struct UIPrefsPrivate UIPrefsPrivate;
+
+struct UIPrefs
+{
+ EphyDialog parent;
+ UIPrefsPrivate *priv;
+};
+
+struct UIPrefsClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType ui_prefs_get_type (void);
+
+EphyDialog *ui_prefs_new (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/window-commands.c b/src/window-commands.c
new file mode 100644
index 000000000..cef1d675c
--- /dev/null
+++ b/src/window-commands.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "ephy-shell.h"
+#include "window-commands.h"
+#include "find-dialog.h"
+#include "print-dialog.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-utils.h"
+#include "pdm-dialog.h"
+#include "toolbar.h"
+#include "ephy-toolbar-editor.h"
+#include "ephy-bookmarks-editor.h"
+#include "ephy-new-bookmark.h"
+
+#include <string.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <bonobo/bonobo-i18n.h>
+#include <libgnomeui/gnome-about.h>
+#include <libgnome/gnome-help.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkeditable.h>
+
+#define AVAILABLE_TOOLBAR_ITEMS \
+ "new=std_toolitem(item=new);" \
+ "back=std_toolitem(item=back);" \
+ "back_history=navigation_history(direction=back);" \
+ "up=std_toolitem(item=up);" \
+ "up_history=navigation_history(direction=up);" \
+ "forward=std_toolitem(item=forward);" \
+ "forward_history=navigation_history(direction=forward);" \
+ "stop=std_toolitem(item=stop);" \
+ "reload=std_toolitem(item=reload);" \
+ "home=std_toolitem(item=home);" \
+ "favicon=favicon;" \
+ "location=location;" \
+ "go=std_toolitem(item=go);" \
+ "zoom=zoom;" \
+ "spinner=spinner;" \
+ "separator;"
+
+
+
+void
+window_cmd_edit_find (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+ dialog = ephy_window_get_find_dialog (window);
+
+ g_object_ref (dialog);
+
+ ephy_dialog_show (dialog);
+}
+
+static void
+print_dialog_preview_cb (PrintDialog *dialog,
+ EphyWindow *window)
+{
+ ephy_window_set_chrome (window, EMBED_CHROME_PPVIEWTOOLBARON);
+}
+
+void
+window_cmd_file_print (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ dialog = print_dialog_new_with_parent (GTK_WIDGET(window),
+ embed, NULL);
+ g_signal_connect (G_OBJECT(dialog),
+ "preview",
+ G_CALLBACK (print_dialog_preview_cb),
+ window);
+ ephy_dialog_set_modal (dialog, TRUE);
+ ephy_dialog_show (dialog);
+}
+
+void
+window_cmd_go_back (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_go_back (embed);
+}
+
+void
+window_cmd_go_up (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_go_up (embed);
+}
+
+void
+window_cmd_file_send_to (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ char *url;
+ EphyTab *tab;
+ EphyEmbed *embed;
+ char *location;
+ char *title;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab);
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (tab);
+
+ location = gnome_vfs_escape_string (ephy_tab_get_location (tab));
+ if (ephy_embed_get_title (embed, &title) == G_OK)
+ {
+ char *tmp = gnome_vfs_escape_string (title);
+ g_free (title);
+ title = tmp;
+ }
+ else
+ {
+ title = gnome_vfs_escape_string (_("Check this out!"));
+ }
+
+ url = g_strconcat ("mailto:",
+ "?Subject=", title,
+ "&Body=", location, NULL);
+
+ ephy_embed_load_url (embed, url);
+
+ g_free (title);
+ g_free (location);
+ g_free (url);
+}
+
+void
+window_cmd_go_forward (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_go_forward (embed);
+}
+
+void
+window_cmd_go_go (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ Toolbar *tb;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ tb = ephy_window_get_toolbar (window);
+
+ if (tb)
+ {
+ char *location = toolbar_get_location (tb);
+ ephy_window_load_url (window, location);
+ g_free (location);
+ }
+}
+
+void
+window_cmd_go_home (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+ char *location;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ location = eel_gconf_get_string (CONF_GENERAL_HOMEPAGE);
+ g_return_if_fail (location != NULL);
+
+ ephy_embed_load_url (embed, location);
+
+ g_free (location);
+}
+
+void
+window_cmd_go_myportal (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_load_url (embed, "myportal:");
+}
+
+void
+window_cmd_go_location (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ ephy_window_activate_location (window);
+}
+
+void
+window_cmd_go_stop (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_stop_load (embed);
+}
+
+void
+window_cmd_go_reload (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_reload (embed, EMBED_RELOAD_NORMAL);
+}
+
+void
+window_cmd_new (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ ephy_shell_new_tab (ephy_shell, window, tab, NULL,
+ EPHY_NEW_TAB_HOMEPAGE |
+ EPHY_NEW_TAB_JUMP);
+}
+
+void
+window_cmd_new_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab, NULL,
+ EPHY_NEW_TAB_HOMEPAGE |
+ EPHY_NEW_TAB_IN_NEW_WINDOW |
+ EPHY_NEW_TAB_JUMP);
+}
+
+void
+window_cmd_new_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ ephy_shell_new_tab (ephy_shell, window, tab, NULL,
+ EPHY_NEW_TAB_HOMEPAGE |
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW |
+ EPHY_NEW_TAB_JUMP);
+}
+
+void
+window_cmd_bookmarks_edit (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *dialog;
+ EphyBookmarks *bookmarks;
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ g_assert (bookmarks != NULL);
+ dialog = ephy_bookmarks_editor_new (bookmarks, GTK_WINDOW (window));
+ gtk_widget_show (dialog);
+}
+
+void
+window_cmd_bookmarks_add_default (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+ EphyEmbed *embed;
+ EphyBookmarks *bookmarks;
+ GtkWidget *new_bookmark;
+ const char *location;
+ char *title;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab);
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (tab);
+
+ location = ephy_tab_get_location (tab);
+ if (ephy_embed_get_title (embed, &title) != G_OK)
+ {
+ title = _("Untitled");
+ }
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ new_bookmark = ephy_new_bookmark_new
+ (bookmarks, GTK_WINDOW (window), location);
+ ephy_new_bookmark_set_title
+ (EPHY_NEW_BOOKMARK (new_bookmark), title);
+ gtk_widget_show (new_bookmark);
+}
+
+void
+window_cmd_file_open (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ gchar *dir, *retDir;
+ gchar *file = NULL;
+ GnomeVFSURI *uri;
+ GtkWidget *wmain;
+ EphyEmbedShell *embed_shell;
+ gresult result;
+
+ embed_shell = ephy_shell_get_embed_shell (ephy_shell);
+ g_return_if_fail (embed_shell != NULL);
+
+ wmain = GTK_WIDGET (window);
+ g_return_if_fail (wmain != NULL);
+
+ dir = eel_gconf_get_string (CONF_STATE_OPEN_DIR);
+
+ result = ephy_embed_shell_show_file_picker
+ (embed_shell, wmain,
+ _("Select the file to open"),
+ dir, NULL, modeOpen,
+ &file, NULL, NULL, NULL);
+
+ if (result == G_OK)
+ {
+ uri = gnome_vfs_uri_new (file);
+ if (uri)
+ {
+
+ ephy_window_load_url(window, file);
+
+ retDir = gnome_vfs_uri_extract_dirname (uri);
+
+ /* set default open dir */
+ eel_gconf_set_string (CONF_STATE_OPEN_DIR,
+ retDir);
+
+ g_free (retDir);
+ gnome_vfs_uri_unref (uri);
+ }
+ }
+
+ g_free (dir);
+ g_free (file);
+}
+
+void
+window_cmd_file_save_as (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+ EphyEmbedPersist *persist;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ persist = ephy_embed_persist_new (embed);
+ ephy_embed_persist_set_flags (persist,
+ EMBED_PERSIST_MAINDOC);
+
+ ephy_embed_utils_save (GTK_WIDGET(window),
+ CONF_STATE_SAVE_DIR,
+ TRUE,
+ TRUE,
+ persist);
+
+ g_object_unref (G_OBJECT(persist));
+}
+
+void
+window_cmd_file_close_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ ephy_window_remove_tab (window, tab);
+}
+
+void
+window_cmd_file_close_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ gtk_widget_destroy (GTK_WIDGET(window));
+}
+
+void
+window_cmd_edit_cut (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_cut_clipboard (GTK_EDITABLE (widget));
+ }
+ else
+ {
+ EphyEmbed *embed;
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_selection_cut (embed);
+ }
+}
+
+void
+window_cmd_edit_copy (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_copy_clipboard (GTK_EDITABLE (widget));
+ }
+ else
+ {
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_selection_copy (embed);
+ }
+}
+
+void
+window_cmd_edit_paste (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_paste_clipboard (GTK_EDITABLE (widget));
+ }
+ else
+ {
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_paste (embed);
+ }
+}
+
+void
+window_cmd_edit_select_all (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
+ }
+ else
+ {
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_select_all (embed);
+ }
+}
+
+void
+window_cmd_edit_find_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+
+ dialog = ephy_window_get_find_dialog (window);
+
+ find_dialog_go_next (FIND_DIALOG(dialog), FALSE);
+
+ ephy_window_update_control (window, FindControl);
+}
+
+void
+window_cmd_edit_find_prev (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+
+ dialog = ephy_window_get_find_dialog (window);
+
+ find_dialog_go_prev (FIND_DIALOG(dialog), FALSE);
+
+ ephy_window_update_control (window, FindControl);
+}
+
+void
+window_cmd_view_zoom_in (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char *verbname)
+{
+ EphyEmbed *embed;
+ int zoom;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_zoom_get (embed, &zoom);
+ ephy_window_set_zoom (window, zoom + 10);
+}
+
+void
+window_cmd_view_zoom_out (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+ int zoom;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_zoom_get (embed, &zoom);
+ if (zoom >= 10)
+ {
+ ephy_window_set_zoom (window, zoom - 10);
+ }
+}
+
+void
+window_cmd_view_zoom_normal (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ ephy_window_set_zoom (window, 100);
+}
+
+void
+window_cmd_view_page_source (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ ephy_shell_new_tab (ephy_shell, window, tab, NULL,
+ EPHY_NEW_TAB_VIEW_SOURCE);
+}
+
+void
+window_cmd_tools_history (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ ephy_window_show_history (window);
+}
+
+void
+window_cmd_tools_pdm (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+
+ dialog = pdm_dialog_new (GTK_WIDGET(window));
+
+ ephy_dialog_show (dialog);
+}
+
+void
+window_cmd_edit_prefs (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkDialog *dialog;
+
+ dialog = prefs_dialog_new ();
+ prefs_dialog_show_page (PREFS_DIALOG(dialog),
+ PREFS_PAGE_GENERAL);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (window));
+ gtk_widget_show (GTK_WIDGET(dialog));
+}
+
+static void
+window_cmd_settings_toolbar_editor_revert_clicked_cb (GtkButton *b, EphyTbEditor *tbe)
+{
+ gchar *def;
+
+ g_return_if_fail (EPHY_IS_TB_EDITOR (tbe));
+
+ eel_gconf_unset (CONF_TOOLBAR_SETUP);
+ def = eel_gconf_get_string (CONF_TOOLBAR_SETUP);
+ if (def)
+ {
+ EphyToolbar *current;
+ EphyToolbar *avail;
+ current = ephy_tb_editor_get_toolbar (tbe);
+ ephy_toolbar_parse (current, def);
+ g_free (def);
+
+ avail = ephy_tb_editor_get_available (tbe);
+ g_object_ref (avail);
+ ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS);
+ ephy_tb_editor_set_available (tbe, avail);
+ g_object_unref (avail);
+ }
+
+}
+
+static void
+window_cmd_settings_toolbar_editor_current_changed_cb (EphyToolbar *tb, gpointer data)
+{
+ gchar *current_str;
+
+ g_return_if_fail (EPHY_IS_TOOLBAR (tb));
+
+ current_str = ephy_toolbar_to_string (tb);
+ eel_gconf_set_string (CONF_TOOLBAR_SETUP, current_str);
+ g_free (current_str);
+}
+
+void
+window_cmd_settings_toolbar_editor (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ static EphyTbEditor *tbe = NULL;
+ EphyToolbar *avail;
+ EphyToolbar *current;
+ gchar *current_str;
+ GtkButton *revert_button;
+
+ avail = ephy_toolbar_new ();
+ ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS);
+
+ current_str = eel_gconf_get_string (CONF_TOOLBAR_SETUP);
+ current = ephy_toolbar_new ();
+ if (current_str)
+ {
+ ephy_toolbar_parse (current, current_str);
+ g_free (current_str);
+ }
+
+ if (!tbe)
+ {
+ tbe = ephy_tb_editor_new ();
+ g_object_add_weak_pointer (G_OBJECT (tbe),
+ (void **)&tbe);
+ ephy_tb_editor_set_parent (tbe,
+ GTK_WIDGET(window));
+ }
+ else
+ {
+ ephy_tb_editor_show (tbe);
+ return;
+ }
+
+ ephy_tb_editor_set_toolbar (tbe, current);
+ ephy_tb_editor_set_available (tbe, avail);
+ g_object_unref (avail);
+ g_object_unref (current);
+
+ g_signal_connect (current, "changed",
+ G_CALLBACK (window_cmd_settings_toolbar_editor_current_changed_cb), NULL);
+
+ revert_button = ephy_tb_editor_get_revert_button (tbe);
+ gtk_widget_show (GTK_WIDGET (revert_button));
+
+ g_signal_connect (revert_button, "clicked",
+ G_CALLBACK (window_cmd_settings_toolbar_editor_revert_clicked_cb), tbe);
+
+ ephy_tb_editor_show (tbe);
+}
+
+void
+window_cmd_help_about (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ static GtkWidget *about = NULL;
+
+ static gchar *authors[] = {
+ "Marco Pesenti Gritti <mpeseng@tin.it>",
+ NULL
+ };
+
+ gchar *documenters[] = {
+ NULL
+ };
+
+ /* Translator credits */
+ gchar *translator_credits = _("translator_credits");
+
+ if (about != NULL)
+ {
+ gdk_window_show(about->window);
+ gdk_window_raise(about->window);
+ return;
+ }
+
+ about = gnome_about_new(
+ _("Epiphany"), VERSION,
+ /* Translators: Please change the (C) to a real
+ * copyright character if your character set allows it
+ * (Hint: iso-8859-1 is one of the character sets that
+ * has this symbol). */
+ _("Copyright (C) 2002 Marco Pesenti Gritti"),
+ _("A GNOME browser based on Mozilla"),
+ (const char **)authors,
+ (const char **)documenters,
+ strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL,
+ NULL);
+
+ gtk_window_set_transient_for (GTK_WINDOW (about),
+ GTK_WINDOW (window));
+ g_object_add_weak_pointer (G_OBJECT (about), (gpointer *)&about);
+ gtk_widget_show (about);
+}
+
+void
+window_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname)
+{
+ EphyWindow *window = data->data;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ g_print (data->encoding);
+ ephy_embed_set_charset (embed, data->encoding);
+}
+
+void
+window_cmd_tabs_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GList *tabs;
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ tabs = ephy_window_get_tabs (window);
+ g_return_if_fail (tab != NULL);
+
+ tabs = g_list_find (tabs, (gpointer)tab);
+ tabs = tabs->next;
+
+ if (tabs)
+ {
+ tab = EPHY_TAB (tabs->data);
+ ephy_window_jump_to_tab (window, tab);
+ g_list_free (tabs);
+ }
+}
+
+void
+window_cmd_tabs_previous (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GList *tabs;
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ tabs = ephy_window_get_tabs (window);
+ g_return_if_fail (tab != NULL);
+
+ tabs = g_list_find (tabs, (gpointer)tab);
+ tabs = tabs->prev;
+
+ if (tabs)
+ {
+ tab = EPHY_TAB (tabs->data);
+ ephy_window_jump_to_tab (window, tab);
+ g_list_free (tabs);
+ }
+}
+
+void
+window_cmd_tabs_move_left (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+}
+
+void window_cmd_tabs_move_right (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+}
+
+void
+window_cmd_tabs_detach (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+ GtkWidget *src_page;
+ EphyWindow *new_win;
+
+ if (g_list_length (ephy_window_get_tabs (window)) <= 1) {
+ return;
+ }
+
+ tab = ephy_window_get_active_tab (window);
+ src_page = GTK_WIDGET (ephy_tab_get_embed (tab));
+ new_win = ephy_window_new ();
+ ephy_notebook_move_page (EPHY_NOTEBOOK (ephy_window_get_notebook (window)),
+ EPHY_NOTEBOOK (ephy_window_get_notebook (new_win)),
+ src_page, 0);
+ ephy_tab_set_window (tab, new_win);
+ gtk_widget_show (GTK_WIDGET (new_win));
+}
+
+void
+window_cmd_help_manual (BonoboUIComponent *uic,
+ char *filename,
+ const char* verbname)
+{
+ GError *error;
+ GtkWidget *dialog;
+
+ error = NULL;
+ gnome_help_display ("Ephy.xml", NULL, &error);
+
+ if (error)
+ {
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("There was an error displaying help: \n%s"),
+ error->message);
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_widget_show (dialog);
+ g_error_free (error);
+ }
+}
diff --git a/src/window-commands.h b/src/window-commands.h
new file mode 100644
index 000000000..df05a4d50
--- /dev/null
+++ b/src/window-commands.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-window.h"
+#include "ephy-embed-utils.h"
+
+#include <bonobo/bonobo-ui-component.h>
+
+void window_cmd_edit_find (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_print (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_stop (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_back (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_forward (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_go (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_up (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_home (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_myportal (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_location (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_reload (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_new (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_new_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_new_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_bookmarks_add_default (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_bookmarks_edit (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_open (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_save_as (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_send_to (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_close_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_close_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_cut (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_copy (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_paste (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_select_all (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_find_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_find_prev (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_zoom_in (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_zoom_out (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_zoom_normal(BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_page_source(BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tools_history (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tools_pdm (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_prefs (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void
+window_cmd_settings_toolbar_editor (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_help_about (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname);
+
+void window_cmd_tabs_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_previous (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_move_left (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_move_right (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_detach (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_help_manual (BonoboUIComponent *uic,
+ char *filename,
+ const char* verbname);
+