Commit 253ce5aa authored by Xan Lopez's avatar Xan Lopez

Import adblock extension into the source tree

This commit imports the adblock extension from 'epiphany-extensions'
with as few modifications as possible. Further modifications and
simplifications are possible, but for now we just load it
unconditionally, enabled.

We have it in the src/ directory because it depends on some high-level
objects in Epiphany (EphyExtension, EphyWindow), but in the future
we'll probably move it to embed/, transforming it from an extension
into just the specific implementation of our EphyAdblockManager
object.

https://bugzilla.gnome.org/show_bug.cgi?id=681657
parent 892cab7e
......@@ -17,7 +17,9 @@ header_DATA = \
$(INST_H_FILES)
NOINST_H_FILES = \
adblock-ui.h \
ephy-action-helper.h \
ephy-adblock-extension.h \
ephy-combined-stop-reload-action.h \
ephy-encoding-dialog.h \
ephy-encoding-menu.h \
......@@ -37,6 +39,7 @@ NOINST_H_FILES = \
pdm-dialog.h \
popup-commands.h \
prefs-dialog.h \
uri-tester.h \
window-commands.h
INST_H_FILES = \
......@@ -51,7 +54,9 @@ INST_H_FILES = \
$(NULL)
libephymain_la_SOURCES = \
adblock-ui.c \
ephy-action-helper.c \
ephy-adblock-extension.c \
ephy-completion-model.c \
ephy-completion-model.h \
ephy-combined-stop-reload-action.c \
......@@ -79,6 +84,7 @@ libephymain_la_SOURCES = \
popup-commands.c \
prefs-dialog.c \
window-commands.c \
uri-tester.c \
$(INST_H_FILES) \
$(NOINST_H_FILES) \
$(NULL)
......@@ -112,6 +118,7 @@ libephymain_la_CFLAGS = \
$(AM_CFLAGS)
UI_FILES = \
resources/adblock.ui \
resources/epiphany-bookmark-editor-ui.xml \
resources/epiphany-history-window-ui.xml \
resources/epiphany-ui.xml \
......
/*
* Copyright © 2011 Igalia S.L.
*
* 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.
*
* Some parts of this file based on the Midori's 'adblock' extension,
* licensed with the GNU Lesser General Public License 2.1, Copyright
* (C) 2009-2010 Christian Dywan <christian@twotoasts.de> and 2009
* Alexander Butenko <a.butenka@gmail.com>. Check Midori's web site
* at http://www.twotoasts.de
*
* 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 "adblock-ui.h"
#include "ephy-adblock.h"
#include "ephy-adblock-manager.h"
#include "ephy-debug.h"
#include "ephy-embed-shell.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#define ADBLOCK_UI_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE((object), TYPE_ADBLOCK_UI, AdblockUIPrivate))
#define ADBLOCK_FILTER_VALID(__filter) \
(__filter && (g_str_has_prefix (__filter, "http") \
|| g_str_has_prefix (__filter, "file")))
struct _AdblockUIPrivate
{
GtkWidget *dialog;
/* The dialog buttons. */
GtkEntry *new_filter;
GtkButton *add, *edit, *remove;
/* Data. */
GtkTreeView *treeview;
GtkTreeSelection *selection;
GtkListStore *store;
/* The uri tester. */
UriTester *tester;
/* Whether something has actually changed. */
gboolean dirty;
};
enum
{
PROP_0,
PROP_TESTER,
};
enum
{
COL_FILTER_URI,
N_COLUMNS
};
G_DEFINE_DYNAMIC_TYPE (AdblockUI, adblock_ui, EPHY_TYPE_DIALOG);
/* Private functions. */
static gboolean
adblock_ui_foreach_save (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GSList **filters)
{
char *filter = NULL;
gtk_tree_model_get (model, iter, COL_FILTER_URI, &filter, -1);
*filters = g_slist_prepend (*filters, filter);
return FALSE;
}
static void
adblock_ui_save (AdblockUI *dialog)
{
GSList *filters = NULL;
gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->priv->store),
(GtkTreeModelForeachFunc)adblock_ui_foreach_save,
&filters);
uri_tester_set_filters (dialog->priv->tester, filters);
}
static void
adblock_ui_response_cb (GtkWidget *widget,
int response,
AdblockUI *dialog)
{
if (response == GTK_RESPONSE_CLOSE && dialog->priv->dirty)
{
EphyAdBlockManager *manager;
adblock_ui_save (dialog);
/* Ask uri tester to reload all its patterns. */
uri_tester_reload (dialog->priv->tester);
/* Ask manager to emit a signal that rules have changed. */
manager = EPHY_ADBLOCK_MANAGER (ephy_embed_shell_get_adblock_manager (embed_shell));
g_signal_emit_by_name (manager, "rules_changed", NULL);
}
g_object_unref (dialog);
}
static void
adblock_ui_add_filter (AdblockUI *dialog)
{
GtkTreeIter iter;
const char *new_filter = gtk_entry_get_text (dialog->priv->new_filter);
if (ADBLOCK_FILTER_VALID (new_filter))
{
GtkListStore *store = dialog->priv->store;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, COL_FILTER_URI, new_filter, -1);
/* Makes the pattern field blank. */
gtk_entry_set_text (dialog->priv->new_filter, "");
dialog->priv->dirty = TRUE;
}
else
{
GtkWidget *error_dialog = NULL;
error_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog->priv->dialog),
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"%s",
_("Invalid filter"));
gtk_dialog_run (GTK_DIALOG (error_dialog));
gtk_widget_destroy (error_dialog);
gtk_entry_set_text (dialog->priv->new_filter, "");
}
}
static void
adblock_ui_add_cb (GtkButton *button,
AdblockUI *dialog)
{
adblock_ui_add_filter (dialog);
}
static void
adblock_ui_edit_cb (GtkButton *button,
AdblockUI *dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreeSelection *selection;
selection = dialog->priv->selection;
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
char* path = gtk_tree_model_get_string_from_iter (model, &iter);
GtkTreePath* tree_path = gtk_tree_path_new_from_string (path);
GtkTreeView *treeview = dialog->priv->treeview;
GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview,
COL_FILTER_URI);
gtk_tree_view_set_cursor (treeview, tree_path, column, TRUE);
gtk_tree_path_free (tree_path);
g_free (path);
}
}
static void
adblock_ui_remove_cb (GtkButton *button,
AdblockUI *dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreeSelection *selection;
selection = dialog->priv->selection;
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_list_store_remove (GTK_LIST_STORE(model), &iter);
gtk_entry_set_text (dialog->priv->new_filter, "");
dialog->priv->dirty = TRUE;
}
}
static void
adblock_ui_cell_edited_cb (GtkCellRendererText *cell,
char *path_string,
char *new_filter,
AdblockUI *dialog)
{
GtkTreeModel *model = GTK_TREE_MODEL (dialog->priv->store);
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
GtkTreeIter iter;
gtk_tree_model_get_iter (model, &iter, path);
gtk_list_store_set (dialog->priv->store, &iter, COL_FILTER_URI, new_filter, -1);
gtk_tree_path_free (path);
dialog->priv->dirty = TRUE;
}
static void
adblock_ui_build_treeview (AdblockUI *dialog)
{
GtkCellRenderer *renderer;
dialog->priv->store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING);
renderer = gtk_cell_renderer_text_new ();
g_object_set(renderer, "editable", TRUE, NULL);
g_signal_connect(renderer,
"edited",
(GCallback) adblock_ui_cell_edited_cb,
(gpointer)dialog);
gtk_tree_view_insert_column_with_attributes (dialog->priv->treeview,
COL_FILTER_URI, _("Filter URI"),
renderer,
"text", COL_FILTER_URI,
NULL);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (dialog->priv->store),
COL_FILTER_URI,
GTK_SORT_ASCENDING);
gtk_tree_view_set_model (dialog->priv->treeview, GTK_TREE_MODEL (dialog->priv->store));
gtk_tree_view_set_search_column (dialog->priv->treeview, COL_FILTER_URI);
g_object_unref (dialog->priv->store);
dialog->priv->selection = gtk_tree_view_get_selection (dialog->priv->treeview);
gtk_tree_selection_set_mode (dialog->priv->selection, GTK_SELECTION_SINGLE);
dialog->priv->dirty = FALSE;
}
static void
adblock_ui_populate_store (AdblockUI *dialog)
{
GSList *filters = NULL;
GSList *item = NULL;
const char *filter_uri = NULL;
GtkTreeIter iter;
filters = uri_tester_get_filters (dialog->priv->tester);
for (item = filters; item; item = g_slist_next (item))
{
filter_uri = (const char *) item->data;
gtk_list_store_append (dialog->priv->store, &iter);
gtk_list_store_set (dialog->priv->store, &iter, COL_FILTER_URI, filter_uri, -1);
}
}
static void
adblock_ui_init (AdblockUI *dialog)
{
LOG ("AdblockUI initialising");
dialog->priv = ADBLOCK_UI_GET_PRIVATE (dialog);
}
static void
adblock_ui_constructed (GObject *object)
{
AdblockUI *dialog;
AdblockUIPrivate *priv;
EphyDialog *edialog;
dialog = ADBLOCK_UI (object);
edialog = EPHY_DIALOG (object);
priv = dialog->priv;
ephy_dialog_construct (EPHY_DIALOG (edialog),
"/org/gnome/epiphany/adblock.ui",
"adblock-ui",
GETTEXT_PACKAGE);
ephy_dialog_get_controls (edialog,
"adblock-ui", &priv->dialog,
"new_filter_entry", &priv->new_filter,
"treeview", &priv->treeview,
"add_button", &priv->add,
"edit_button", &priv->edit,
"remove_button", &priv->remove,
NULL);
g_signal_connect (priv->dialog, "response",
G_CALLBACK (adblock_ui_response_cb), dialog);
g_signal_connect (priv->add, "clicked",
G_CALLBACK (adblock_ui_add_cb), dialog);
g_signal_connect (priv->edit, "clicked",
G_CALLBACK (adblock_ui_edit_cb), dialog);
g_signal_connect (priv->remove, "clicked",
G_CALLBACK (adblock_ui_remove_cb), dialog);
g_signal_connect (priv->new_filter, "activate",
G_CALLBACK (adblock_ui_add_cb), dialog);
/* Build and fill. */
adblock_ui_build_treeview (dialog);
adblock_ui_populate_store (dialog);
/* Chain up. */
G_OBJECT_CLASS (adblock_ui_parent_class)->constructed (object);
}
static void
adblock_ui_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
AdblockUI *dialog = ADBLOCK_UI (object);
switch (prop_id)
{
case PROP_TESTER:
dialog->priv->tester = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
adblock_ui_class_init (AdblockUIClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = adblock_ui_constructed;
object_class->set_property = adblock_ui_set_property;
g_object_class_install_property
(object_class,
PROP_TESTER,
g_param_spec_object ("tester",
"UriTester",
"UriTester",
TYPE_URI_TESTER,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (object_class, sizeof (AdblockUIPrivate));
}
static void adblock_ui_class_finalize (AdblockUIClass *klass)
{
}
/* Public functions. */
void adblock_ui_register (GTypeModule *module)
{
adblock_ui_register_type (module);
}
AdblockUI *
adblock_ui_new (UriTester *tester)
{
return g_object_new (TYPE_ADBLOCK_UI,
"tester", tester,
NULL);
}
/*
* Copyright © 2011 Igalia S.L.
*
* 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 ADBLOCK_UI_H
#define ADBLOCK_UI_H
#include "ephy-dialog.h"
#include "uri-tester.h"
#include <glib-object.h>
#include <glib.h>
G_BEGIN_DECLS
#define TYPE_ADBLOCK_UI (adblock_ui_get_type ())
#define ADBLOCK_UI(o) (G_TYPE_CHECK_INSTANCE_CAST((o), TYPE_ADBLOCK_UI, AdblockUI))
#define ADBLOCK_UI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TYPE_ADBLOCK_UI, AdblockUIClass))
#define IS_ADBLOCK_UI(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), TYPE_ADBLOCK_UI))
#define IS_ADBLOCK_UI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), TYPE_ADBLOCK_UI))
#define ADBLOCK_UI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), TYPE_ADBLOCK_UI, AdblockUIClass))
typedef struct _AdblockUI AdblockUI;
typedef struct _AdblockUIClass AdblockUIClass;
typedef struct _AdblockUIPrivate AdblockUIPrivate;
struct _AdblockUI
{
EphyDialog parent;
/*< private >*/
AdblockUIPrivate *priv;
};
struct _AdblockUIClass
{
EphyDialogClass parent_class;
};
GType adblock_ui_get_type (void);
void adblock_ui_register (GTypeModule *module);
AdblockUI *adblock_ui_new (UriTester *tester);
G_END_DECLS
#endif
/*
* Copyright © 2011 Igalia S.L.
*
* 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.
*
* Some parts of this file based on the previous 'adblock' extension,
* licensed with the GNU General Public License 2 and later versions,
* Copyright (C) 2003 Marco Pesenti Gritti, Christian Persch.
*
* 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-adblock-extension.h"
#include "adblock-ui.h"
#include "ephy-adblock.h"
#include "ephy-adblock-manager.h"
#include "ephy-debug.h"
#include "ephy-embed-shell.h"
#include "ephy-extension.h"
#include "ephy-file-helpers.h"
#include "ephy-window.h"
#include "uri-tester.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#define EPHY_ADBLOCK_EXTENSION_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_ADBLOCK_EXTENSION, EphyAdblockExtensionPrivate))
#define WINDOW_DATA_KEY "EphyAdblockExtensionWindowData"
#define STATUSBAR_EVBOX_KEY "EphyAdblockExtensionStatusbarEvbox"
#define EXTENSION_KEY "EphyAdblockExtension"
#define AD_BLOCK_ICON_NAME "ad-blocked"
typedef struct
{
EphyAdblockExtension *extension;
EphyWindow *window;
GtkActionGroup *action_group;
guint ui_id;
} WindowData;
struct EphyAdblockExtensionPrivate
{
UriTester *tester;
AdblockUI *ui;
};
static void ephy_adblock_extension_iface_init (EphyExtensionIface *iface);
static void ephy_adblock_adblock_iface_init (EphyAdBlockIface *iface);
G_DEFINE_TYPE_WITH_CODE (EphyAdblockExtension,
ephy_adblock_extension,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (EPHY_TYPE_ADBLOCK,
ephy_adblock_adblock_iface_init)
G_IMPLEMENT_INTERFACE (EPHY_TYPE_EXTENSION,
ephy_adblock_extension_iface_init))
/* Private functions. */
static void
ephy_adblock_extension_init (EphyAdblockExtension *extension)
{
LOG ("EphyAdblockExtension initialising");
extension->priv = EPHY_ADBLOCK_EXTENSION_GET_PRIVATE (extension);
extension->priv->tester = uri_tester_new ();
}
static void
ephy_adblock_extension_dispose (GObject *object)
{
EphyAdblockExtension *extension = NULL;
LOG ("EphyAdblockExtension disposing");
extension = EPHY_ADBLOCK_EXTENSION (object);
g_clear_object (&extension->priv->ui);
g_clear_object (&extension->priv->tester);
G_OBJECT_CLASS (ephy_adblock_extension_parent_class)->dispose (object);
}
static void
ephy_adblock_extension_finalize (GObject *object)
{
LOG ("EphyAdblockExtension finalising");
G_OBJECT_CLASS (ephy_adblock_extension_parent_class)->finalize (object);
}
static void
ephy_adblock_extension_class_init (EphyAdblockExtensionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = ephy_adblock_extension_dispose;
object_class->finalize = ephy_adblock_extension_finalize;
g_type_class_add_private (object_class, sizeof (EphyAdblockExtensionPrivate));
}
static gboolean
ephy_adblock_impl_should_load (EphyAdBlock *blocker,
EphyEmbed *embed,
const char *url,
AdUriCheckType type)
{
EphyAdblockExtension *self = NULL;
EphyWebView* web_view = NULL;
const char *address = NULL;
LOG ("ephy_adblock_impl_should_load checking %s", url);
self = EPHY_ADBLOCK_EXTENSION (blocker);
g_return_val_if_fail (self != NULL, TRUE);
web_view = ephy_embed_get_web_view (embed);
address = ephy_web_view_get_address (web_view);
return !uri_tester_test_uri (self->priv->tester, url, address, type);
}
static void
ephy_adblock_impl_edit_rule (EphyAdBlock *blocker,
const char *url,
gboolean allowed)
{
EphyAdblockExtension *self = NULL;
EphyAdblockExtensionPrivate *priv = NULL;
LOG ("ephy_adblock_impl_edit_rule %s with state %d", url, allowed);
self = EPHY_ADBLOCK_EXTENSION (blocker);
priv = self->priv;
if (priv->ui == NULL)
{
AdblockUI **ui;
/*
* TODO: url and allowed should be passed to the UI,
* so the user can actually do something with it.
*/
priv->ui = adblock_ui_new (priv->tester);
ui = &priv->ui;
g_object_add_weak_pointer ((gpointer)priv->ui,
(gpointer *) ui);
ephy_dialog_set_parent (EPHY_DIALOG (priv->ui), NULL);
}
ephy_dialog_show (EPHY_DIALOG (priv->ui));
}
static void
ephy_adblock_adblock_iface_init (EphyAdBlockIface *iface)
{
iface->should_load = ephy_adblock_impl_should_load;
iface->edit_rule = ephy_adblock_impl_edit_rule;
}
static void
ephy_adblock_extension_edit_cb (GtkAction *action, EphyWindow *window)
{
WindowData *data = NULL;
EphyAdblockExtensionPrivate *priv = NULL;
data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY);
g_return_if_fail (data != NULL);
priv = data->extension->priv;
if (priv->ui == NULL)
{
AdblockUI **ui;
priv->ui = adblock_ui_new (priv->tester);
ui = &priv->ui;
g_object_add_weak_pointer ((gpointer)priv->ui,
(gpointer *) ui);
}
ephy_dialog_set_parent (EPHY_DIALOG (priv->ui), GTK_WIDGET (window));
ephy_dialog_show (EPHY_DIALOG (priv->ui));
}
static const GtkActionEntry edit_entries[] = {
{ "EphyAdblockExtensionEdit", NULL,
N_("Ad Blocker"), NULL,
N_("Configure Ad Blocker filters"),
G_CALLBACK (ephy_adblock_extension_edit_cb) }
};
static void
impl_attach_window (EphyExtension *ext,
EphyWindow *window)
{
WindowData *data = NULL;
GtkUIManager *manager = NULL;
/* Add adblock editor's menu entry. */
data = g_new (WindowData, 1);
g_object_set_data_full (G_OBJECT (window),
WINDOW_DATA_KEY,
data,
g_free);
data->extension = EPHY_ADBLOCK_EXTENSION (ext);
data->window = window;
data->action_group = gtk_action_group_new ("EphyAdblockExtension");
gtk_action_group_set_translation_domain (data->action_group,
GETTEXT_PACKAGE);
gtk_action_group_add_actions (data->action_group, edit_entries,
G_N_ELEMENTS(edit_entries), window);
manager = GTK_UI_MANAGER (ephy_window_get_ui_manager (window));
gtk_ui_manager_insert_action_group (manager, data->action_group, -1);
/* UI manager references the new action group. */
g_object_unref (data->action_group);
data->ui_id = gtk_ui_manager_new_merge_id (manager);
gtk_ui_manager_add_ui (manager,
data->ui_id,
"/ui/PagePopup/ExtensionsMenu",
"EphyAdblockExtensionEdit",
"EphyAdblockExtensionEdit",
GTK_UI_MANAGER_MENUITEM,
FALSE);
/* Remember the xtension attached to that window. */
g_object_set_data (G_OBJECT (window), EXTENSION_KEY, ext);
}
static void
impl_detach_window (EphyExtension *ext,
EphyWindow *window)
{
WindowData *data = NULL;
GtkUIManager *manager = NULL;