From 611e5407571e19353a98292d953e90e63073ba61 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sun, 17 Oct 2004 13:39:12 +0000 Subject: R lib/ephy-module-loader.c: R lib/ephy-module-loader.h: A 2004-10-17 Christian Persch * lib/Makefile.am: R lib/ephy-module-loader.c: R lib/ephy-module-loader.h: A lib/ephy-module.c: (ephy_module_get_type), (ephy_module_load), (ephy_module_unload), (ephy_module_get_path), (ephy_module_new_object), (ephy_module_init), (ephy_module_finalize), (ephy_module_class_init), (ephy_module_new): A lib/ephy-module.h: s/EphyModuleLoader/EphyModule/g since "loader" now means something different. A lib/ephy-loader.c: (ephy_loader_get_type), (ephy_loader_type), (ephy_loader_get_object), (ephy_loader_release_object): A lib/ephy-loader.h: Generic object loader. A lib/ephy-shlib-loader.c: (ephy_shlib_loader_get_type), (free_loader_data), (ephy_shlib_loader_init), (ephy_shlib_loader_finalize), (find_library), (find_object), (idle_unref), (impl_get_object), (impl_release_object), (ephy_shlib_loader_iface_init), (ephy_shlib_loader_class_init): A lib/ephy-shlib-loader.h: A .so loader. * src/Makefile.am: * src/ephy-extensions-manager.c: (ephy_extensions_manager_load), (ephy_extensions_manager_unload), (ephy_extensions_manager_register), (ephy_extensions_manager_get_extensions), (free_extension_info), (free_loader_info), (find_extension_info), (ephy_extensions_manager_load_file), (find_loader), (get_loader_for_type), (attach_window), (load_extension), (detach_window), (unload_extension), (ephy_extensions_manager_load_dir), (active_extensions_notifier), (ephy_extensions_manager_init), (ephy_extensions_manager_finalize), (impl_attach_window), (impl_detach_window), (ephy_extensions_manager_class_init): * src/ephy-extensions-manager.h: Read extension descriptions from .xml, load them with the specified loader (for now, just only .so is supported). * src/ephy-shell.c: (ephy_shell_finalize), (ephy_shell_get_session), (ephy_shell_get_extensions_manager): Minor API change in extensions manager. * data/epiphany.schemas.in: Add extensions-manager-ui as default active extension. 2004-10-10 Marco Pesenti Gritti --- ChangeLog | 58 ++- data/epiphany.schemas.in | 7 +- lib/Makefile.am | 9 +- lib/ephy-loader.c | 71 ++++ lib/ephy-loader.h | 66 ++++ lib/ephy-module-loader.c | 205 ---------- lib/ephy-module-loader.h | 47 --- lib/ephy-module.c | 205 ++++++++++ lib/ephy-module.h | 48 +++ lib/ephy-shlib-loader.c | 256 +++++++++++++ lib/ephy-shlib-loader.h | 57 +++ src/Makefile.am | 2 +- src/ephy-extensions-manager.c | 867 ++++++++++++++++++++++++++++++------------ src/ephy-extensions-manager.h | 44 ++- src/ephy-shell.c | 38 +- 15 files changed, 1446 insertions(+), 534 deletions(-) create mode 100644 lib/ephy-loader.c create mode 100644 lib/ephy-loader.h delete mode 100644 lib/ephy-module-loader.c delete mode 100644 lib/ephy-module-loader.h create mode 100644 lib/ephy-module.c create mode 100644 lib/ephy-module.h create mode 100644 lib/ephy-shlib-loader.c create mode 100644 lib/ephy-shlib-loader.h diff --git a/ChangeLog b/ChangeLog index 3fb92f670..fce11e0cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,60 @@ +2004-10-17 Christian Persch + + * lib/Makefile.am: + R lib/ephy-module-loader.c: + R lib/ephy-module-loader.h: + A lib/ephy-module.c: (ephy_module_get_type), (ephy_module_load), + (ephy_module_unload), (ephy_module_get_path), + (ephy_module_new_object), (ephy_module_init), + (ephy_module_finalize), (ephy_module_class_init), + (ephy_module_new): + A lib/ephy-module.h: + + s/EphyModuleLoader/EphyModule/g since "loader" now means something + different. + + A lib/ephy-loader.c: (ephy_loader_get_type), (ephy_loader_type), + (ephy_loader_get_object), (ephy_loader_release_object): + A lib/ephy-loader.h: + + Generic object loader. + + A lib/ephy-shlib-loader.c: (ephy_shlib_loader_get_type), + (free_loader_data), (ephy_shlib_loader_init), + (ephy_shlib_loader_finalize), (find_library), (find_object), + (idle_unref), (impl_get_object), (impl_release_object), + (ephy_shlib_loader_iface_init), (ephy_shlib_loader_class_init): + A lib/ephy-shlib-loader.h: + + A .so loader. + + * src/Makefile.am: + * src/ephy-extensions-manager.c: (ephy_extensions_manager_load), + (ephy_extensions_manager_unload), + (ephy_extensions_manager_register), + (ephy_extensions_manager_get_extensions), (free_extension_info), + (free_loader_info), (find_extension_info), + (ephy_extensions_manager_load_file), (find_loader), + (get_loader_for_type), (attach_window), (load_extension), + (detach_window), (unload_extension), + (ephy_extensions_manager_load_dir), (active_extensions_notifier), + (ephy_extensions_manager_init), (ephy_extensions_manager_finalize), + (impl_attach_window), (impl_detach_window), + (ephy_extensions_manager_class_init): + * src/ephy-extensions-manager.h: + + Read extension descriptions from .xml, load them with the specified + loader (for now, just only .so is supported). + + * src/ephy-shell.c: (ephy_shell_finalize), + (ephy_shell_get_session), (ephy_shell_get_extensions_manager): + + Minor API change in extensions manager. + + * data/epiphany.schemas.in: + + Add extensions-manager-ui as default active extension. + 2004-10-10 Marco Pesenti Gritti reviewed by: Christian Persch @@ -636,4 +693,3 @@ Merging pre-gnome-2-10 branch to HEAD. Splitting ChangeLog. - diff --git a/data/epiphany.schemas.in b/data/epiphany.schemas.in index b51537072..ed72f722f 100644 --- a/data/epiphany.schemas.in +++ b/data/epiphany.schemas.in @@ -196,11 +196,10 @@ epiphany list string + [extensions-manager-ui] - Loaded extensions - Partial filenames of extensions to load. For example, if a desired - extension's filename is "libgesturesextension.so", add "gestures" to the - list. + Active extensions + Lists the active extensions. diff --git a/lib/Makefile.am b/lib/Makefile.am index 8a7c8ff79..c90f51ac3 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -24,16 +24,18 @@ NOINST_H_FILES = \ ephy-gui.h \ ephy-langs.h \ ephy-marshal.h \ - ephy-module-loader.h \ + ephy-module.h \ ephy-node-filter.h \ ephy-node-common.h \ ephy-prefs.h \ + ephy-shlib-loader.h \ ephy-string.h \ ephy-stock-icons.h \ ephy-zoom.h INST_H_FILES = \ ephy-dialog.h \ + ephy-loader.h \ ephy-node.h \ ephy-node-db.h \ ephy-state.h @@ -48,7 +50,8 @@ libephymisc_la_SOURCES = \ ephy-glade.c \ ephy-gui.c \ ephy-langs.c \ - ephy-module-loader.c \ + ephy-loader.c \ + ephy-module.c \ ephy-marshal.c \ ephy-node.c \ ephy-node.h \ @@ -56,6 +59,7 @@ libephymisc_la_SOURCES = \ ephy-node-common.h \ ephy-node-db.c \ ephy-prefs.h \ + ephy-shlib-loader.c \ ephy-state.c \ ephy-string.c \ ephy-stock-icons.c \ @@ -75,4 +79,3 @@ ephy-marshal.h: ephy-marshal.list EXTRA_DIST = \ ephy-marshal.list - diff --git a/lib/ephy-loader.c b/lib/ephy-loader.c new file mode 100644 index 000000000..cbd19fce9 --- /dev/null +++ b/lib/ephy-loader.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-loader.h" + +GType +ephy_loader_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyLoaderIface), + NULL, + NULL, + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "EphyLoader", + &our_info, 0); + } + + return type; +} + +const char * +ephy_loader_type (const EphyLoader *loader) +{ + EphyLoaderIface *iface = EPHY_LOADER_GET_IFACE (loader); + return iface->type; +} + +GObject * +ephy_loader_get_object (EphyLoader *loader, + GData **attributes) +{ + EphyLoaderIface *iface = EPHY_LOADER_GET_IFACE (loader); + return iface->get_object (loader, attributes); +} + +void +ephy_loader_release_object (EphyLoader *loader, + GObject *object) +{ + EphyLoaderIface *iface = EPHY_LOADER_GET_IFACE (loader); + iface->release_object (loader, object); +} diff --git a/lib/ephy-loader.h b/lib/ephy-loader.h new file mode 100644 index 000000000..c987bb636 --- /dev/null +++ b/lib/ephy-loader.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + * $Id$ + */ + +#ifndef EPHY_LOADER_H +#define EPHY_LOADER_H + +#include +#include + +G_BEGIN_DECLS + +#define EPHY_TYPE_LOADER (ephy_loader_get_type ()) +#define EPHY_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_LOADER, EphyLoader)) +#define EPHY_LOADER_IFACE(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_LOADER, EphyLoaderIface)) +#define EPHY_IS_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_LOADER)) +#define EPHY_IS_LOADER_IFACE(iface) (G_TYPE_CHECK_CLASS_TYPE ((iface), EPHY_TYPE_LOADER)) +#define EPHY_LOADER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EPHY_TYPE_LOADER, EphyLoaderIface)) + +typedef struct _EphyLoader EphyLoader; +typedef struct _EphyLoaderIface EphyLoaderIface; + +struct _EphyLoaderIface +{ + GTypeInterface base_iface; + + /* Identifier */ + const char *type; + + /* Methods */ + GObject * (* get_object) (EphyLoader *loader, + GData **attributes); + void (* release_object) (EphyLoader *loader, + GObject *object); +}; + +GType ephy_loader_get_type (void); + +const char *ephy_loader_type (const EphyLoader *loader); + +GObject *ephy_loader_get_object (EphyLoader *loader, + GData **attributes); + +void ephy_loader_release_object (EphyLoader *loader, + GObject *object); + +G_END_DECLS + +#endif diff --git a/lib/ephy-module-loader.c b/lib/ephy-module-loader.c deleted file mode 100644 index 2cd72fd89..000000000 --- a/lib/ephy-module-loader.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2003 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. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ephy-module-loader.h" -#include "ephy-file-helpers.h" -#include "ephy-debug.h" - -#include - -typedef struct _EphyModuleLoaderClass EphyModuleLoaderClass; - -struct _EphyModuleLoaderClass -{ - GTypeModuleClass parent_class; -}; - -struct _EphyModuleLoader -{ - GTypeModule parent_instance; - - GModule *library; - - char *path; - GType type; -}; - -typedef GType (*register_module_fn) (GTypeModule *); - -static void ephy_module_loader_init (EphyModuleLoader *action); -static void ephy_module_loader_class_init (EphyModuleLoaderClass *class); -static void ephy_module_loader_finalize (GObject *object); - -static GObjectClass *parent_class = NULL; - -GType -ephy_module_loader_get_type (void) -{ - static GType type = 0; - - if (!type) - { - static const GTypeInfo type_info = - { - sizeof (EphyModuleLoaderClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) ephy_module_loader_class_init, - (GClassFinalizeFunc) NULL, - NULL, - sizeof (EphyModuleLoader), - 0, /* n_preallocs */ - (GInstanceInitFunc) ephy_module_loader_init, - }; - - type = g_type_register_static (G_TYPE_TYPE_MODULE, - "EphyModuleLoader", - &type_info, 0); - } - - return type; -} - -EphyModuleLoader * -ephy_module_loader_new (const char *path) -{ - EphyModuleLoader *result; - - if (path == NULL || path[0] == '\0') - { - return NULL; - } - - result = g_object_new (EPHY_TYPE_MODULE_LOADER, NULL); - - g_type_module_set_name (G_TYPE_MODULE (result), path); - result->path = g_strdup (path); - - return result; -} - -static gboolean -ephy_module_loader_load (GTypeModule *module) -{ - EphyModuleLoader *loader = EPHY_MODULE_LOADER (module); - register_module_fn register_module; - - LOG ("ephy_module_loader_load %s", loader->path) - - loader->library = g_module_open (loader->path, 0); - - if (!loader->library) - { - g_warning (g_module_error()); - - return FALSE; - } - - /* extract symbols from the lib */ - if (!g_module_symbol (loader->library, "register_module", - (void *) ®ister_module)) - { - g_warning (g_module_error()); - g_module_close (loader->library); - - return FALSE; - } - - g_assert (register_module != NULL); - - loader->type = register_module (module); - - if (loader->type == 0) - { - return FALSE; - } - - return TRUE; -} - -static void -ephy_module_loader_unload (GTypeModule *module) -{ - EphyModuleLoader *loader = EPHY_MODULE_LOADER (module); - - g_module_close (loader->library); - - loader->library = NULL; - loader->type = 0; -} - -const char * -ephy_module_loader_get_path (EphyModuleLoader *loader) -{ - g_return_val_if_fail (EPHY_IS_MODULE_LOADER (loader), NULL); - - return loader->path; -} - -static void -ephy_module_loader_class_init (EphyModuleLoaderClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - GTypeModuleClass *loader_class = G_TYPE_MODULE_CLASS (class); - - parent_class = (GObjectClass *) g_type_class_peek_parent (class); - - object_class->finalize = ephy_module_loader_finalize; - - loader_class->load = ephy_module_loader_load; - loader_class->unload = ephy_module_loader_unload; -} - -static void -ephy_module_loader_init (EphyModuleLoader *loader) -{ - LOG ("EphyModuleLoader initialising") - - loader->library = NULL; - loader->path = NULL; - loader->type = 0; -} - -static void -ephy_module_loader_finalize (GObject *object) -{ - EphyModuleLoader *loader = EPHY_MODULE_LOADER (object); - - LOG ("EphyModuleLoader finalising") - - g_free (loader->path); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -GObject * -ephy_module_loader_factory (EphyModuleLoader *loader) -{ - if (loader->type == 0) - { - return NULL; - } - - return g_object_new (loader->type, NULL); -} diff --git a/lib/ephy-module-loader.h b/lib/ephy-module-loader.h deleted file mode 100644 index fe25712a7..000000000 --- a/lib/ephy-module-loader.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2003 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. - * - * $Id$ - */ - -#ifndef EPHY_MODULE_LOADER_H -#define EPHY_MODULE_LOADER_H - -#include - -G_BEGIN_DECLS - -#define EPHY_TYPE_MODULE_LOADER (ephy_module_loader_get_type ()) -#define EPHY_MODULE_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_MODULE_LOADER, EphyModuleLoader)) -#define EPHY_MODULE_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_MODULE_LOADER, EphyModuleLoaderClass)) -#define EPHY_IS_MODULE_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_MODULE_LOADER)) -#define EPHY_IS_MODULE_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EPHY_TYPE_MODULE_LOADER)) -#define EPHY_MODULE_LOADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_MODULE_LOADER, EphyModuleLoaderClass)) - -typedef struct _EphyModuleLoader EphyModuleLoader; - -GType ephy_module_loader_get_type (void); - -EphyModuleLoader *ephy_module_loader_new (const char *path); - -const char *ephy_module_loader_get_path (EphyModuleLoader *loader); - -GObject *ephy_module_loader_factory (EphyModuleLoader *loader); - -G_END_DECLS - -#endif diff --git a/lib/ephy-module.c b/lib/ephy-module.c new file mode 100644 index 000000000..60c96f1f2 --- /dev/null +++ b/lib/ephy-module.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-module.h" +#include "ephy-file-helpers.h" +#include "ephy-debug.h" + +#include + +typedef struct _EphyModuleClass EphyModuleClass; + +struct _EphyModuleClass +{ + GTypeModuleClass parent_class; +}; + +struct _EphyModule +{ + GTypeModule parent_instance; + + GModule *library; + + char *path; + GType type; +}; + +typedef GType (*EphyModuleRegisterFunc) (GTypeModule *); + +static void ephy_module_init (EphyModule *action); +static void ephy_module_class_init (EphyModuleClass *class); + +static GObjectClass *parent_class = NULL; + +GType +ephy_module_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + static const GTypeInfo type_info = + { + sizeof (EphyModuleClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ephy_module_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EphyModule), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_module_init, + }; + + type = g_type_register_static (G_TYPE_TYPE_MODULE, + "EphyModule", + &type_info, 0); + } + + return type; +} + +static gboolean +ephy_module_load (GTypeModule *gmodule) +{ + EphyModule *module = EPHY_MODULE (gmodule); + EphyModuleRegisterFunc register_func; + + LOG ("Loading %s", module->path) + + module->library = g_module_open (module->path, 0); + + if (module->library == NULL) + { + g_warning (g_module_error()); + + return FALSE; + } + + /* extract symbols from the lib */ + if (!g_module_symbol (module->library, "register_module", + (void *) ®ister_func)) + { + g_warning (g_module_error()); + g_module_close (module->library); + + return FALSE; + } + + g_assert (register_func); + + module->type = register_func (gmodule); + + if (module->type == 0) + { + return FALSE; + } + + return TRUE; +} + +static void +ephy_module_unload (GTypeModule *gmodule) +{ + EphyModule *module = EPHY_MODULE (gmodule); + + LOG ("Unloading %s", module->path) + + g_module_close (module->library); + + module->library = NULL; + module->type = 0; +} + +const char * +ephy_module_get_path (EphyModule *module) +{ + g_return_val_if_fail (EPHY_IS_MODULE (module), NULL); + + return module->path; +} + +GObject * +ephy_module_new_object (EphyModule *module) +{ + LOG ("Creating object of type %s", g_type_name (module->type)) + + if (module->type == 0) + { + return NULL; + } + + return g_object_new (module->type, NULL); +} + +static void +ephy_module_init (EphyModule *module) +{ + LOG ("EphyModule %p initialising", module) +} + +static void +ephy_module_finalize (GObject *object) +{ + EphyModule *module = EPHY_MODULE (object); + + LOG ("EphyModule %p finalising", module) + + g_free (module->path); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_module_class_init (EphyModuleClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class); + + parent_class = (GObjectClass *) g_type_class_peek_parent (class); + + object_class->finalize = ephy_module_finalize; + + module_class->load = ephy_module_load; + module_class->unload = ephy_module_unload; +} + +EphyModule * +ephy_module_new (const char *path) +{ + EphyModule *result; + + if (path == NULL || path[0] == '\0') + { + return NULL; + } + + result = g_object_new (EPHY_TYPE_MODULE, NULL); + + g_type_module_set_name (G_TYPE_MODULE (result), path); + result->path = g_strdup (path); + + return result; +} diff --git a/lib/ephy-module.h b/lib/ephy-module.h new file mode 100644 index 000000000..aaacbff63 --- /dev/null +++ b/lib/ephy-module.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + * $Id$ + */ + +#ifndef EPHY_MODULE_H +#define EPHY_MODULE_H + +#include + +G_BEGIN_DECLS + +#define EPHY_TYPE_MODULE (ephy_module_get_type ()) +#define EPHY_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_MODULE, EphyModule)) +#define EPHY_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_MODULE, EphyModuleClass)) +#define EPHY_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_MODULE)) +#define EPHY_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EPHY_TYPE_MODULE)) +#define EPHY_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_MODULE, EphyModuleClass)) + +typedef struct _EphyModule EphyModule; + +GType ephy_module_get_type (void); + +EphyModule *ephy_module_new (const char *path); + +const char *ephy_module_get_path (EphyModule *module); + +GObject *ephy_module_new_object (EphyModule *module); + +G_END_DECLS + +#endif diff --git a/lib/ephy-shlib-loader.c b/lib/ephy-shlib-loader.c new file mode 100644 index 000000000..68276bb67 --- /dev/null +++ b/lib/ephy-shlib-loader.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-shlib-loader.h" +#include "ephy-loader.h" +#include "ephy-module.h" +#include "ephy-debug.h" + +#include + +#define DATA_KEY "EphyShlibLoader::LoaderData" + +typedef struct +{ + EphyModule *module; + GObject *object; +} LoaderData; + +static GQuark library_quark = 0; + +#define EPHY_SHLIB_LOADER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SHLIB_LOADER, EphyShlibLoaderPrivate)) + +struct _EphyShlibLoaderPrivate +{ + GSList *data; +}; + +static void ephy_shlib_loader_class_init (EphyShlibLoaderClass *klass); +static void ephy_shlib_loader_iface_init (EphyLoaderIface *iface); +static void ephy_shlib_loader_init (EphyShlibLoader *loader); + +static GObjectClass *parent_class = NULL; + +GType +ephy_shlib_loader_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyShlibLoaderClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_shlib_loader_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyShlibLoader), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_shlib_loader_init + }; + + static const GInterfaceInfo loader_info = + { + (GInterfaceInitFunc) ephy_shlib_loader_iface_init, + NULL, + NULL + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EphyShlibLoader", + &our_info, 0); + + g_type_add_interface_static (type, + EPHY_TYPE_LOADER, + &loader_info); + } + + return type; +} + +static void +free_loader_data (LoaderData *data) +{ + g_return_if_fail (data != NULL); + + /* data->module must NOT be unreffed! */ + + if (data->object != NULL) + { + g_object_unref (data->object); + } + + g_free (data); +} + +static void +ephy_shlib_loader_init (EphyShlibLoader *loader) +{ + loader->priv = EPHY_SHLIB_LOADER_GET_PRIVATE (loader); + + LOG ("EphyShlibLoader initialising") +} + +static void +ephy_shlib_loader_finalize (GObject *object) +{ + EphyShlibLoader *loader = EPHY_SHLIB_LOADER (object); + + LOG ("EphyShlibLoader finalising") + + g_slist_foreach (loader->priv->data, (GFunc) free_loader_data, NULL); + g_slist_free (loader->priv->data); + + parent_class->finalize (object); +} + +static int +find_library (const LoaderData *data, + const char *library) +{ + return strcmp (ephy_module_get_path (data->module), library); +} + +static int +find_object (const LoaderData *data, + const GObject *object) +{ + return data->object != object; +} + +static gboolean +idle_unref (GObject *object) +{ + g_object_unref (object); + + return FALSE; +} + +static GObject * +impl_get_object (EphyLoader *eloader, + GData **attributes) +{ + EphyShlibLoader *loader = EPHY_SHLIB_LOADER (eloader); + GSList *l; + LoaderData *data = NULL; + const char *library; + + library = g_datalist_id_get_data (attributes, library_quark); + if (library == NULL) + { + g_warning ("NULL library name!\n"); + return NULL; + } + + l = g_slist_find_custom (loader->priv->data, library, + (GCompareFunc) find_library); + + if (l != NULL) + { + data = l->data; + g_return_val_if_fail (data != NULL, NULL); + + if (data->object != NULL) + { + return g_object_ref (data->object); + } + } + else + { + data = g_new0 (LoaderData, 1); + loader->priv->data = g_slist_prepend (loader->priv->data, data); + } + + if (data->module == NULL) + { + data->module = ephy_module_new (library); + } + + g_return_val_if_fail (data->object == NULL, data->object); + + if (g_type_module_use (G_TYPE_MODULE (data->module)) == FALSE) + { + g_warning ("Could not load extension file at %s\n", + ephy_module_get_path (data->module)); + return NULL; + } + + data->object = ephy_module_new_object (data->module); + + g_type_module_unuse (G_TYPE_MODULE (data->module)); + + if (data->object != NULL) + { + g_object_set_data (G_OBJECT (data->object), DATA_KEY, data); + } + + return data->object; +} + +static void +impl_release_object (EphyLoader *eloader, + GObject *object) +{ + EphyShlibLoader *loader = EPHY_SHLIB_LOADER (eloader); + GSList *l; + LoaderData *data; + + l = g_slist_find_custom (loader->priv->data, object, + (GCompareFunc) find_object); + g_return_if_fail (l != NULL); + data = l->data; + + /* FIXME: should we consider those extensions broken? + * Only unref the extension in the idle loop; if the extension has its + * own functions queued in the idle loop, the functions must exist in + * memory before being called. + */ + g_idle_add ((GSourceFunc) idle_unref, data->object); + data->object = NULL; +} + +static void +ephy_shlib_loader_iface_init (EphyLoaderIface *iface) +{ + iface->type = "shlib"; + iface->get_object = impl_get_object; + iface->release_object = impl_release_object; +} + +static void +ephy_shlib_loader_class_init (EphyShlibLoaderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_shlib_loader_finalize; + + g_type_class_add_private (object_class, sizeof (EphyShlibLoaderPrivate)); + + library_quark = g_quark_from_string ("library"); +} diff --git a/lib/ephy-shlib-loader.h b/lib/ephy-shlib-loader.h new file mode 100644 index 000000000..6f3d04977 --- /dev/null +++ b/lib/ephy-shlib-loader.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * 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. + * + * $Id$ + */ + +#ifndef EPHY_SHLIB_LOADER_H +#define EPHY_SHLIB_LOADER_H + +#include + +G_BEGIN_DECLS + +#define EPHY_TYPE_SHLIB_LOADER (ephy_shlib_loader_get_type ()) +#define EPHY_SHLIB_LOADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_SHLIB_LOADER, EphyShlibLoader)) +#define EPHY_SHLIB_LOADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_SHLIB_LOADER, EphyShlibLoaderClass)) +#define EPHY_IS_SHLIB_LOADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_SHLIB_LOADER)) +#define EPHY_IS_SHLIB_LOADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_SHLIB_LOADER)) +#define EPHY_SHLIB_LOADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_SHLIB_LOADER, EphyShlibLoaderClass)) + +typedef struct _EphyShlibLoader EphyShlibLoader; +typedef struct _EphyShlibLoaderPrivate EphyShlibLoaderPrivate; +typedef struct _EphyShlibLoaderClass EphyShlibLoaderClass; + +struct _EphyShlibLoaderClass +{ + GObjectClass parent_class; +}; + +struct _EphyShlibLoader +{ + GObject parent_instance; + + /*< private >*/ + EphyShlibLoaderPrivate *priv; +}; + +GType ephy_shlib_loader_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 93816cc44..a3c87a061 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,7 +44,6 @@ NOINST_H_FILES = \ ephy-automation.h \ ephy-encoding-dialog.h \ ephy-encoding-menu.h \ - ephy-extensions-manager.h \ ephy-favicon-action.h \ ephy-go-action.h \ ephy-history-window.h \ @@ -61,6 +60,7 @@ NOINST_H_FILES = \ INST_H_FILES = \ ephy-extension.h \ + ephy-extensions-manager.h \ ephy-notebook.h \ ephy-session.h \ ephy-shell.h \ diff --git a/src/ephy-extensions-manager.c b/src/ephy-extensions-manager.c index 7b66f289e..0fc15bcbd 100644 --- a/src/ephy-extensions-manager.c +++ b/src/ephy-extensions-manager.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2003 Marco Pesenti Gritti - * Copyright (C) 2003 Christian Persch + * Copyright (C) 2003, 2004 Christian Persch + * Copyright (C) 2004 Adam Hooper * * 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 @@ -25,12 +26,16 @@ #include "ephy-extensions-manager.h" +#include "ephy-loader.h" +#include "ephy-shlib-loader.h" + +#include "ephy-node-db.h" #include "ephy-shell.h" -#include "ephy-session.h" /* Weird (session is an extension) but it works */ -#include "ephy-module-loader.h" +#include "eel-gconf-extensions.h" +#include "ephy-file-helpers.h" #include "ephy-debug.h" -#include "eel-gconf-extensions.h" +#include #include #include @@ -40,18 +45,46 @@ #define EPHY_EXTENSIONS_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_EXTENSIONS_MANAGER, EphyExtensionsManagerPrivate)) -struct EphyExtensionsManagerPrivate +struct _EphyExtensionsManagerPrivate { - GHashTable *extensions; - GSList *internal_extensions; + gboolean initialised; + + GList *data; + GList *factories; + GList *extensions; + GList *windows; guint active_extensions_notifier_id; }; typedef struct { - EphyModuleLoader *loader; /* NULL if never loaded */ - EphyExtension *extension; /* NULL if unloaded */ -} ExtInfo; + EphyExtensionInfo info; + guint version; + gboolean load_deferred; + gboolean load_failed; + + xmlChar *gettext_domain; + xmlChar *locale_directory; + xmlChar *loader_type; + GData *loader_attributes; + + EphyLoader *loader; /* NULL if never loaded */ + GObject *extension; /* NULL if unloaded */ +} ExtensionInfo; + +typedef struct +{ + char *type; + EphyLoader *loader; +} LoaderInfo; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; static GObjectClass *parent_class = NULL; @@ -98,103 +131,29 @@ ephy_extensions_manager_get_type (void) return type; } -static void -free_ext_info (ExtInfo *info) -{ - if (info->extension) - { - g_object_unref (info->extension); - } - g_free (info); -} - -static void -windows_foreach (GFunc func, EphyExtension *extension) -{ - EphySession *session; - GList *windows; - - session = EPHY_SESSION (ephy_shell_get_session (ephy_shell)); - - windows = ephy_session_get_windows (session); - - g_list_foreach (windows, func, extension); - - g_list_free (windows); -} - -static void -attach_window (EphyWindow *window, - EphyExtension *extension) -{ - ephy_extension_attach_window (extension, window); -} - -static void -detach_window (EphyWindow *window, - EphyExtension *extension) -{ - ephy_extension_detach_window (extension, window); -} - -static EphyExtension * -instantiate_extension (EphyModuleLoader *loader) -{ - EphyExtension *extension; - - extension = EPHY_EXTENSION (ephy_module_loader_factory (loader)); - - if (EPHY_IS_EXTENSION (extension)) - { - windows_foreach ((GFunc) attach_window, extension); - - return extension; - } - - return NULL; -} - -static void -real_load (ExtInfo *info) -{ - if (info->extension != NULL) return; - - if (g_type_module_use (G_TYPE_MODULE (info->loader)) == FALSE) - { - g_warning ("Could not load extension file at %s\n", - ephy_module_loader_get_path (info->loader)); - return; - } - - info->extension = instantiate_extension (info->loader); - - if (info->extension == NULL) - { - g_warning ("Could not load extension at %s\n", - ephy_module_loader_get_path (info->loader)); - } - - g_type_module_unuse (G_TYPE_MODULE (info->loader)); -} - /** * ephy_extensions_manager_load: * @manager: an #EphyExtensionsManager - * @filename: filename of an extension to load, minus "lib" and "extension.so" + * @name: identifier of the extension to load * - * Loads the @filename extension. + * Loads the @name extension. **/ void ephy_extensions_manager_load (EphyExtensionsManager *manager, - const char *filename) + const char *identifier) { GSList *gconf_exts; + g_return_if_fail (EPHY_IS_EXTENSIONS_MANAGER (manager)); + g_return_if_fail (identifier != NULL); + + LOG ("Adding '%s' to extensions", identifier) + gconf_exts = eel_gconf_get_string_list (CONF_LOADED_EXTENSIONS); - if (!g_slist_find_custom (gconf_exts, filename, (GCompareFunc) strcmp)) + if (!g_slist_find_custom (gconf_exts, identifier, (GCompareFunc) strcmp)) { - gconf_exts = g_slist_prepend (gconf_exts, g_strdup (filename)); + gconf_exts = g_slist_prepend (gconf_exts, g_strdup (identifier)); eel_gconf_set_string_list (CONF_LOADED_EXTENSIONS, gconf_exts); } @@ -203,28 +162,12 @@ ephy_extensions_manager_load (EphyExtensionsManager *manager, g_slist_free (gconf_exts); } -static void -real_unload (ExtInfo *info) -{ - if (info->extension == NULL) return; /* not loaded */ - - windows_foreach ((GFunc) detach_window, info->extension); - - /* - * Only unref the extension in the idle loop; if the extension has its - * own functions queued in the idle loop, the functions must exist in - * memory before being called. - */ - g_idle_add ((GSourceFunc) g_object_unref, info->extension); - info->extension = NULL; -} - /** * ephy_extensions_manager_unload: * @manager: an #EphyExtensionsManager - * @filename: filename of extension to unload, minus "lib" and "extension.so" + * @name: filename of extension to unload, minus "lib" and "extension.so" * - * Unloads the extension specified by @filename. + * Unloads the extension specified by @name. * * The extension with the same filename can afterwards be reloaded. However, * if any GTypes within the extension have changed parent types, Epiphany must @@ -232,14 +175,19 @@ real_unload (ExtInfo *info) **/ void ephy_extensions_manager_unload (EphyExtensionsManager *manager, - const char *filename) + const char *identifier) { GSList *gconf_exts; GSList *l; - + + g_return_if_fail (EPHY_IS_EXTENSIONS_MANAGER (manager)); + g_return_if_fail (identifier != NULL); + + LOG ("Removing '%s' from extensions", identifier) + gconf_exts = eel_gconf_get_string_list (CONF_LOADED_EXTENSIONS); - l = g_slist_find_custom (gconf_exts, filename, (GCompareFunc) strcmp); + l = g_slist_find_custom (gconf_exts, identifier, (GCompareFunc) strcmp); if (l != NULL) { @@ -255,119 +203,537 @@ ephy_extensions_manager_unload (EphyExtensionsManager *manager, } /** - * ephy_extensions_manager_add: + * ephy_extensions_manager_register: * @manager: an #EphyExtensionsManager - * @type: GType of the extension to add + * @object: an Extension * - * Creates a new instance of @type (which must be an #EphyExtension) and adds - * it to @manager. This is only used to load internal Epiphany extensions. - * - * Return value: a new instance of @type + * Registers @object with the extensions manager. @object must implement the + * #EphyExtension interface. **/ -EphyExtension * -ephy_extensions_manager_add (EphyExtensionsManager *manager, - GType type) +void +ephy_extensions_manager_register (EphyExtensionsManager *manager, + GObject *object) { - EphyExtension *extension; + g_return_if_fail (EPHY_IS_EXTENSIONS_MANAGER (manager)); + g_return_if_fail (EPHY_IS_EXTENSION (object)); - LOG ("adding extensions of type %s", g_type_name (type)) - - extension = EPHY_EXTENSION (g_object_new (type, NULL)); - if (!EPHY_IS_EXTENSION (extension)) - { - g_object_unref (extension); + LOG ("Registering internal extension of type %s", + g_type_name (((GTypeClass *) object)->g_type)) - return NULL; - } + manager->priv->extensions = g_list_prepend (manager->priv->extensions, + g_object_ref (object)); +} - manager->priv->internal_extensions = - g_slist_append (manager->priv->internal_extensions, extension); - return extension; +/** + * ephy_extensions_manager_get_extensions: + * @manager: an #EphyExtensionsManager + * + * Returns the list of known extensions. + * + * Returns: a list of #EphyExtensionInfo + **/ +GList * +ephy_extensions_manager_get_extensions (EphyExtensionsManager *manager) +{ + return g_list_copy (manager->priv->data); } static void -sync_one_extension (const char *name, - ExtInfo *info, - GSList *wanted_exts) +free_extension_info (ExtensionInfo *info) { - if (g_slist_find_custom (wanted_exts, name, (GCompareFunc) strcmp)) + EphyExtensionInfo *einfo = (EphyExtensionInfo *) info; + + g_free (einfo->identifier); + xmlFree ((xmlChar *) einfo->name); + xmlFree ((xmlChar *) einfo->description); + g_list_foreach (einfo->authors, (GFunc) xmlFree, NULL); + g_list_free (einfo->authors); + xmlFree ((xmlChar *) einfo->url); + xmlFree ((xmlChar *) info->gettext_domain); + xmlFree ((xmlChar *) info->locale_directory); + xmlFree ((xmlChar *) info->loader_type); + g_datalist_clear (&info->loader_attributes); + + if (info->extension != NULL) { - real_load (info); + g_return_if_fail (info->loader != NULL); + + ephy_loader_release_object (info->loader, info->extension); } - else + if (info->loader != NULL) { - real_unload (info); + g_object_unref (info->loader); } + + g_free (info); } static void -ephy_extensions_manager_sync_gconf (EphyExtensionsManager *manager) +free_loader_info (LoaderInfo *info) { - GSList *wanted_exts; - - wanted_exts = eel_gconf_get_string_list (CONF_LOADED_EXTENSIONS); - - g_hash_table_foreach (manager->priv->extensions, - (GHFunc) sync_one_extension, - wanted_exts); + g_free (info->type); + g_object_unref (info->loader); + g_free (info); +} - g_slist_foreach (wanted_exts, (GFunc) g_free, NULL); - g_slist_free (wanted_exts); +static int +find_extension_info (const ExtensionInfo *info, + const char *identifier) +{ + return strcmp (info->info.identifier, identifier); } +typedef enum +{ + STATE_START, + STATE_STOP, + STATE_ERROR, + STATE_EXTENSION, + STATE_NAME, + STATE_DESCRIPTION, + STATE_VERSION, + STATE_AUTHOR, + STATE_URL, + STATE_GETTEXT_DOMAIN, + STATE_LOCALE_DIRECTORY, + STATE_LOADER, + STATE_LOADER_ATTRIBUTE, + STATE_LOAD_DEFERRED, +} ParserState; + static void ephy_extensions_manager_load_file (EphyExtensionsManager *manager, const char *dir, const char *filename) { - ExtInfo *info; - char *name; - char *path; + xmlTextReaderPtr reader; + ParserState state = STATE_START; + GQuark attr_quark = 0; + EphyExtensionInfo *einfo; + ExtensionInfo *info; + int ret; + char *identifier, *dot, *path; + + LOG ("Loading description file '%s'", filename) + + identifier = g_path_get_basename (filename); + dot = strstr (identifier, ".xml"); + g_return_if_fail (dot != NULL); + *dot = '\0'; + + if (g_list_find_custom (manager->priv->data, identifier, + (GCompareFunc) find_extension_info) != NULL) + { + g_warning ("Extension description for '%s' already read!\n", + identifier); + g_free (identifier); + return; + } - /* Must match "libBLAHextension.so" */ - if (!g_str_has_prefix (filename, "lib") - || !g_str_has_suffix (filename, "extension." G_MODULE_SUFFIX)) + path = g_build_filename (dir, filename, NULL); + if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) { + g_warning ("'%s' doesn't exist\n", filename); + g_free (identifier); + g_free (path); return; } + + reader = xmlNewTextReaderFilename (path); + g_free (path); - name = g_strndup (filename + 3, - strlen(filename) - 13 - strlen(G_MODULE_SUFFIX)); + if (reader == NULL) + { + g_warning ("Couldn't read '%s'\n", filename); + g_free (identifier); + return; + } + + info = g_new0 (ExtensionInfo, 1); + einfo = (EphyExtensionInfo *) info; + einfo->identifier = identifier; + g_datalist_init (&info->loader_attributes); - if (g_hash_table_lookup (manager->priv->extensions, name) != NULL) + ret = xmlTextReaderRead (reader); + + while (ret == 1) { - /* We already have another version stored */ - g_free (name); + const xmlChar *tag; + xmlReaderTypes type; + + tag = xmlTextReaderConstName (reader); + type = xmlTextReaderNodeType (reader); + + if (state == STATE_LOADER && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "attribute")) + { + xmlChar *name; + + state = STATE_LOADER_ATTRIBUTE; + + name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); + attr_quark = g_quark_from_string ((const char *) name); + xmlFree (name); + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "author")) + { + state = STATE_AUTHOR; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "description")) + { + state = STATE_DESCRIPTION; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "gettext-domain")) + { + state = STATE_GETTEXT_DOMAIN; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "load-deferred")) + { + state = STATE_LOAD_DEFERRED; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "locale-directory")) + { + state = STATE_LOCALE_DIRECTORY; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "name")) + { + state = STATE_NAME; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "url")) + { + state = STATE_URL; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "version")) + { + state = STATE_VERSION; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "loader")) + { + state = STATE_LOADER; + + info->loader_type = xmlTextReaderGetAttribute (reader, (const xmlChar *) "type"); + } + else if (state == STATE_LOADER_ATTRIBUTE && + type == XML_READER_TYPE_TEXT && + attr_quark != 0) + { + xmlChar *value; + + value = xmlTextReaderValue (reader); + + g_datalist_id_set_data_full (&info->loader_attributes, + attr_quark, value, + (GDestroyNotify) xmlFree); + attr_quark = 0; + } + else if (state == STATE_LOADER_ATTRIBUTE && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "attribute")) + { + state = STATE_LOADER; + } + else if (state == STATE_AUTHOR && + type == XML_READER_TYPE_TEXT) + { + einfo->authors = g_list_prepend + (einfo->authors, xmlTextReaderValue (reader)); + } + else if (state == STATE_DESCRIPTION && + type == XML_READER_TYPE_TEXT) + { + + einfo->description = xmlTextReaderValue (reader); + } + else if (state == STATE_GETTEXT_DOMAIN && + type == XML_READER_TYPE_TEXT) + { + info->gettext_domain = xmlTextReaderValue (reader); + } + else if (state == STATE_LOAD_DEFERRED && + type == XML_READER_TYPE_TEXT) + { + const xmlChar *value; + + value = xmlTextReaderConstValue (reader); + info->load_deferred = + (value != NULL && xmlStrEqual (value, (const xmlChar *) "true")); + } + else if (state == STATE_LOCALE_DIRECTORY && + type == XML_READER_TYPE_TEXT) + { + info->locale_directory = xmlTextReaderValue (reader); + } + else if (state == STATE_NAME && + type == XML_READER_TYPE_TEXT) + { + einfo->name = xmlTextReaderValue (reader); + } + else if (state == STATE_VERSION && + type == XML_READER_TYPE_TEXT) + { + info->version = (guint) strtol ((const char *) xmlTextReaderConstValue (reader), NULL, 10); + } + else if (state == STATE_URL && + type == XML_READER_TYPE_TEXT) + { + einfo->url = xmlTextReaderValue (reader); + } + else if (state == STATE_AUTHOR && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "author")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_DESCRIPTION && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "description")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_GETTEXT_DOMAIN && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "gettext-domain")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_LOCALE_DIRECTORY && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "locale-directory")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_LOADER && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "loader")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_NAME && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "name")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_URL && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "url")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_VERSION && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "version")) + { + state = STATE_EXTENSION; + } + else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE || + type == XML_READER_TYPE_WHITESPACE || + type == XML_READER_TYPE_TEXT) + { + /* eat it */ + } + else if (state == STATE_START && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "extension")) + { + state = STATE_EXTENSION; + } + else if (state == STATE_EXTENSION && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, (const xmlChar *) "extension")) + { + state = STATE_STOP; + } + else + { + const xmlChar *content; + + content = xmlTextReaderConstValue (reader); + g_warning ("tag '%s' of type %d in state %d with content '%s' was unexpected!", + tag, type, state, content ? (char *) content : "(null)"); + + state = STATE_ERROR; + break; + } + + ret = xmlTextReaderRead (reader); + } + + xmlFreeTextReader (reader); + + /* sanity check */ + if (ret < 0 || state != STATE_STOP || + einfo->name == NULL || einfo->description == NULL || + info->loader_type == NULL || info->loader_type[0] == '\0') + { + free_extension_info (info); return; } - path = g_build_filename (dir, filename, NULL); + manager->priv->data = g_list_prepend (manager->priv->data, info); +} - info = g_new0 (ExtInfo, 1); - info->loader = ephy_module_loader_new (path); +static int +find_loader (const LoaderInfo *info, + const char *type) +{ + return strcmp (info->type, type); +} - g_free (path); +static EphyLoader * +get_loader_for_type (EphyExtensionsManager *manager, + const char *type) +{ + LoaderInfo *info; + GList *l; + + LOG ("Looking for loader for type '%s'", type) - g_hash_table_insert (manager->priv->extensions, name, info); + l = g_list_find_custom (manager->priv->factories, type, + (GCompareFunc) find_loader); + if (l != NULL) + { + info = (LoaderInfo *) l->data; + return g_object_ref (info->loader); + } + + if (strcmp (type, "shlib") == 0) + { + info = g_new (LoaderInfo, 1); + info->type = g_strdup (type); + info->loader = g_object_new (EPHY_TYPE_SHLIB_LOADER, NULL); + + manager->priv->factories = + g_list_append (manager->priv->factories, info); + + return g_object_ref (info->loader); + } + + /* try to load a loader */ + g_return_val_if_reached (NULL); + + return NULL; } -/** - * ephy_extensions_manager_load_dir: - * @manager: an #EphyExtensionsManager - * @path: directory to load - * - * Searches @path for all files matching the pattern - * "libEXTextension.so" and stores them in @manager, ready to be - * loaded. - **/ -void + +static void +attach_window (EphyWindow *window, + EphyExtension *extension) +{ + ephy_extension_attach_window (extension, window); +} + +static void +load_extension (EphyExtensionsManager *manager, + ExtensionInfo *info) +{ + + EphyLoader *loader; + + g_return_if_fail (info->extension == NULL); + + LOG ("Loading extension '%s'", info->info.identifier) + + /* don't try again */ + if (info->load_failed) return; + + /* get a loader */ + loader = get_loader_for_type (manager, info->loader_type); + if (loader == NULL) + { + g_warning ("No loader found for extension '%s' of type '%s'\n", + info->info.identifier, info->loader_type); + return; + } + + info->loader = loader; + + info->extension = ephy_loader_get_object (loader, + &info->loader_attributes); + + if (info->extension != NULL) + { + manager->priv->extensions = + g_list_prepend (manager->priv->extensions, + g_object_ref (info->extension)); + + g_list_foreach (manager->priv->windows, (GFunc) attach_window, + info->extension); + + info->info.active = TRUE; + + g_signal_emit (manager, signals[CHANGED], 0, info); + } + else + { + info->load_failed = TRUE; + } +} + +static void +detach_window (EphyWindow *window, + EphyExtension *extension) +{ + ephy_extension_detach_window (extension, window); +} + +static void +unload_extension (EphyExtensionsManager *manager, + ExtensionInfo *info) +{ + g_return_if_fail (info->loader != NULL); + g_return_if_fail (info->extension != NULL || info->load_failed); + + LOG ("Unloading extension '%s'", info->info.identifier) + + if (info->load_failed) return; + + g_list_foreach (manager->priv->windows, (GFunc) detach_window, + info->extension); + + manager->priv->extensions = + g_list_remove (manager->priv->extensions, info->extension); + + ephy_loader_release_object (info->loader, G_OBJECT (info->extension)); + g_object_unref (info->extension); + + info->info.active = FALSE; + info->extension = NULL; + + g_signal_emit (manager, signals[CHANGED], 0, info); +} + +static void ephy_extensions_manager_load_dir (EphyExtensionsManager *manager, const char *path) { DIR *d; struct dirent *e; + LOG ("Scanning directory '%s'", path) + + START_PROFILER ("Scanning directory") + d = opendir (path); if (d == NULL) { @@ -375,11 +741,14 @@ ephy_extensions_manager_load_dir (EphyExtensionsManager *manager, } while ((e = readdir (d)) != NULL) { - ephy_extensions_manager_load_file (manager, path, e->d_name); + if (g_str_has_suffix (e->d_name, ".xml")) + { + ephy_extensions_manager_load_file (manager, path, e->d_name); + } } closedir (d); - ephy_extensions_manager_sync_gconf (manager); + STOP_PROFILER ("Scanning directory") } static void @@ -388,57 +757,91 @@ active_extensions_notifier (GConfClient *client, GConfEntry *entry, EphyExtensionsManager *manager) { - ephy_extensions_manager_sync_gconf (manager); + GSList *active_extensions; + GList *l; + gboolean active; + ExtensionInfo *info; + + LOG ("Synching changed list of active extensions") + + active_extensions = eel_gconf_get_string_list (CONF_LOADED_EXTENSIONS); + + for (l = manager->priv->data; l != NULL; l = l->next) + { + info = (ExtensionInfo *) l->data; + + active = (g_slist_find_custom (active_extensions, + info->info.identifier, + (GCompareFunc) strcmp) != NULL); + + LOG ("Extension '%s' is %sactive and %sloaded", + info->info.identifier, + active ? "" : "not ", + info->info.active ? "" : "not ") + + if (active != info->info.active) + { + if (active) + { + load_extension (manager, info); + } + else + { + unload_extension (manager, info); + } + } + } + + g_slist_foreach (active_extensions, (GFunc) g_free, NULL); + g_slist_free (active_extensions); } static void ephy_extensions_manager_init (EphyExtensionsManager *manager) { + char *path; + manager->priv = EPHY_EXTENSIONS_MANAGER_GET_PRIVATE (manager); LOG ("EphyExtensionsManager initialising") - manager->priv->extensions = g_hash_table_new_full - (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, (GDestroyNotify) free_ext_info); + /* load the extensions descriptions */ + path = g_build_filename (ephy_dot_dir (), "extensions", NULL); + ephy_extensions_manager_load_dir (manager, path); + g_free (path); - manager->priv->internal_extensions = NULL; + ephy_extensions_manager_load_dir (manager, EXTENSIONS_DIR); + active_extensions_notifier (NULL, 0, NULL, manager); manager->priv->active_extensions_notifier_id = - eel_gconf_notification_add (CONF_LOADED_EXTENSIONS, - (GConfClientNotifyFunc) - active_extensions_notifier, - manager); + eel_gconf_notification_add + (CONF_LOADED_EXTENSIONS, + (GConfClientNotifyFunc) active_extensions_notifier, + manager); } static void ephy_extensions_manager_finalize (GObject *object) { EphyExtensionsManager *manager = EPHY_EXTENSIONS_MANAGER (object); + EphyExtensionsManagerPrivate *priv = manager->priv; LOG ("EphyExtensionsManager finalising") - g_hash_table_destroy (manager->priv->extensions); + eel_gconf_notification_remove (manager->priv->active_extensions_notifier_id); - g_slist_foreach (manager->priv->internal_extensions, - (GFunc) g_object_unref, NULL); - g_slist_free (manager->priv->internal_extensions); + g_list_foreach (priv->extensions, (GFunc) g_object_unref, NULL); + g_list_free (priv->extensions); - eel_gconf_notification_remove - (manager->priv->active_extensions_notifier_id); + g_list_foreach (priv->factories, (GFunc) free_loader_info, NULL); + g_list_free (priv->factories); - G_OBJECT_CLASS (parent_class)->finalize (object); -} + g_list_foreach (priv->data, (GFunc) free_extension_info, NULL); + g_list_free (priv->data); -static void -attach_window_to_info (const char *key, - ExtInfo *info, - EphyWindow *window) -{ - if (info->extension) - { - ephy_extension_attach_window (info->extension, window); - } + g_list_free (priv->windows); + + parent_class->finalize (object); } static void @@ -447,25 +850,12 @@ impl_attach_window (EphyExtension *extension, { EphyExtensionsManager *manager = EPHY_EXTENSIONS_MANAGER (extension); - LOG ("multiplexing attach_window") + LOG ("Attach") - g_slist_foreach (manager->priv->internal_extensions, - (GFunc) ephy_extension_attach_window, window); + g_list_foreach (manager->priv->extensions, + (GFunc) ephy_extension_attach_window, window); - g_hash_table_foreach (manager->priv->extensions, - (GHFunc) attach_window_to_info, - window); -} - -static void -detach_window_from_info (const char *key, - ExtInfo *info, - EphyWindow *window) -{ - if (info->extension) - { - ephy_extension_detach_window (info->extension, window); - } + manager->priv->windows = g_list_prepend (manager->priv->windows, window); } static void @@ -474,16 +864,14 @@ impl_detach_window (EphyExtension *extension, { EphyExtensionsManager *manager = EPHY_EXTENSIONS_MANAGER (extension); - LOG ("multiplexing detach_window") + LOG ("Detach") - g_object_ref (window); + manager->priv->windows = g_list_remove (manager->priv->windows, window); - g_slist_foreach (manager->priv->internal_extensions, - (GFunc) ephy_extension_detach_window, window); + g_object_ref (window); - g_hash_table_foreach (manager->priv->extensions, - (GHFunc) detach_window_from_info, - window); + g_list_foreach (manager->priv->extensions, + (GFunc) ephy_extension_detach_window, window); g_object_unref (window); } @@ -504,11 +892,16 @@ ephy_extensions_manager_class_init (EphyExtensionsManagerClass *class) object_class->finalize = ephy_extensions_manager_finalize; + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyExtensionsManagerClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + g_type_class_add_private (object_class, sizeof (EphyExtensionsManagerPrivate)); } - -EphyExtensionsManager * -ephy_extensions_manager_new (void) -{ - return EPHY_EXTENSIONS_MANAGER (g_object_new (EPHY_TYPE_EXTENSIONS_MANAGER, NULL)); -} diff --git a/src/ephy-extensions-manager.h b/src/ephy-extensions-manager.h index 3272ff320..d7bc81dcd 100644 --- a/src/ephy-extensions-manager.h +++ b/src/ephy-extensions-manager.h @@ -23,6 +23,7 @@ #define EPHY_EXTENSIONS_MANAGER_H #include "ephy-extension.h" +#include "ephy-node.h" #include #include @@ -36,16 +37,30 @@ G_BEGIN_DECLS #define EPHY_IS_EXTENSIONS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_EXTENSIONS_MANAGER)) #define EPHY_EXTENSIONS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_EXTENSIONS_MANAGER, EphyExtensionsManagerClass)) -typedef struct EphyExtensionsManager EphyExtensionsManager; -typedef struct EphyExtensionsManagerClass EphyExtensionsManagerClass; -typedef struct EphyExtensionsManagerPrivate EphyExtensionsManagerPrivate; +typedef struct _EphyExtensionsManager EphyExtensionsManager; +typedef struct _EphyExtensionsManagerClass EphyExtensionsManagerClass; +typedef struct _EphyExtensionsManagerPrivate EphyExtensionsManagerPrivate; -struct EphyExtensionsManagerClass +typedef struct +{ + char *identifier; + char *name; + char *description; + GList *authors; + char *url; + gboolean active; +} EphyExtensionInfo; + +struct _EphyExtensionsManagerClass { GObjectClass parent_class; + + /* Signals */ + void (* changed) (EphyExtensionsManager *manager, + EphyExtensionInfo *info); }; -struct EphyExtensionsManager +struct _EphyExtensionsManager { GObject parent_instance; @@ -53,21 +68,18 @@ struct EphyExtensionsManager EphyExtensionsManagerPrivate *priv; }; -GType ephy_extensions_manager_get_type (void); - -EphyExtensionsManager *ephy_extensions_manager_new (void); +GType ephy_extensions_manager_get_type (void); -void ephy_extensions_manager_load (EphyExtensionsManager *manager, - const char *filename); +void ephy_extensions_manager_load (EphyExtensionsManager *manager, + const char *identifier); -void ephy_extensions_manager_unload (EphyExtensionsManager *manager, - const char *filename); +void ephy_extensions_manager_unload (EphyExtensionsManager *manager, + const char *identifier); -void ephy_extensions_manager_load_dir (EphyExtensionsManager *manager, - const char *path); +void ephy_extensions_manager_register (EphyExtensionsManager *manager, + GObject *object); -EphyExtension *ephy_extensions_manager_add (EphyExtensionsManager *manager, - GType type); +GList *ephy_extensions_manager_get_extensions (EphyExtensionsManager *manager); G_END_DECLS diff --git a/src/ephy-shell.c b/src/ephy-shell.c index b63f49e21..1e049bb3b 100644 --- a/src/ephy-shell.c +++ b/src/ephy-shell.c @@ -413,18 +413,27 @@ ephy_shell_finalize (GObject *object) /* this will unload the extensions */ LOG ("Unref extension manager") - g_object_unref (shell->priv->extensions_manager); + if (shell->priv->extensions_manager) + { + g_object_unref (shell->priv->extensions_manager); + } + + LOG ("Unref session manager") + if (shell->priv->session) + { + g_object_unref (shell->priv->session); + } LOG ("Unref toolbars model") if (shell->priv->toolbars_model) { - g_object_unref (G_OBJECT (shell->priv->toolbars_model)); + g_object_unref (shell->priv->toolbars_model); } LOG ("Unref fullscreen toolbars model") if (shell->priv->fs_toolbars_model) { - g_object_unref (G_OBJECT (shell->priv->fs_toolbars_model)); + g_object_unref (shell->priv->fs_toolbars_model); } LOG ("Unref Bookmarks Editor"); @@ -605,13 +614,12 @@ ephy_shell_get_session (EphyShell *shell) { EphyExtensionsManager *manager; + shell->priv->session = g_object_new (EPHY_TYPE_SESSION, NULL); + manager = EPHY_EXTENSIONS_MANAGER (ephy_shell_get_extensions_manager (shell)); - - /* Instantiate internal extensions */ - shell->priv->session = - EPHY_SESSION (ephy_extensions_manager_add - (manager, EPHY_TYPE_SESSION)); + ephy_extensions_manager_register (manager, + G_OBJECT (shell->priv->session)); } return G_OBJECT (shell->priv->session); @@ -683,19 +691,9 @@ ephy_shell_get_extensions_manager (EphyShell *es) if (es->priv->extensions_manager == NULL) { - char *path; - /* Instantiate extensions manager */ - es->priv->extensions_manager = ephy_extensions_manager_new (); - - /* load the extensions */ - path = g_build_filename (ephy_dot_dir (), "extensions", NULL); - ephy_extensions_manager_load_dir (es->priv->extensions_manager, - path); - g_free (path); - - ephy_extensions_manager_load_dir (es->priv->extensions_manager, - EXTENSIONS_DIR); + es->priv->extensions_manager = + g_object_new (EPHY_TYPE_EXTENSIONS_MANAGER, NULL); } return G_OBJECT (es->priv->extensions_manager); -- cgit