diff options
author | Marco Pesenti Gritti <mpeseng@src.gnome.org> | 2002-12-31 03:29:24 +0800 |
---|---|---|
committer | Marco Pesenti Gritti <mpeseng@src.gnome.org> | 2002-12-31 03:29:24 +0800 |
commit | 6876ede98282c7db318089bfefb292aa59e55d48 (patch) | |
tree | 76b23252d04da232d0ebf22e53bfe3e022686af9 /src | |
download | gsoc2013-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')
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 (¤t_date, 1); + g_date_set_time (¤t_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 (¤t_date, 1); + break; + /* Last three days */ + case 3: + g_date_subtract_days (¤t_date, 2); + break; + /* Week */ + case 4: + g_date_subtract_days (¤t_date, 7); + break; + /* Month */ + case 5: + g_date_subtract_months (¤t_date, 1); + break; + default: + break; + } + + g_date_to_struct_tm (¤t_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); + |