diff options
Diffstat (limited to 'src/evbp.c')
-rw-r--r-- | src/evbp.c | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/src/evbp.c b/src/evbp.c new file mode 100644 index 0000000..4f95bf2 --- /dev/null +++ b/src/evbp.c @@ -0,0 +1,383 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "evbp.h" +#include "evbp-mime.h" +#include "evbp-debug.h" + +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <npapi.h> +#include <npfunctions.h> +#include <prtypes.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <evince-document.h> + +#ifdef PACKAGE_VERSION +#define EVBP_VERSION PACKAGE_VERSION +#else +#define EVBP_VERSION "" +#endif +#define EVBP_NAME "Evince Plugin" +#define EVBP_DESCRIPTION "Evince Browser Plugin " EVBP_VERSION + +static char *evbp_mime_string = NULL; +static const NPNetscapeFuncs *npn_funcs = NULL; +static gboolean evbp_is_initialized = FALSE; + +static gboolean +evbp_initialize(void) +{ + evbp_debug(NULL); + + /* Some backends don't handle repeated init */ + if (evbp_is_initialized) + return TRUE; + + /* Init glib threads asap */ + if (!g_thread_supported()) + g_thread_init(NULL); + +#ifdef ENABLE_NLS + /* Initialize the i18n stuff */ + bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); +#endif + + /* Initialize gtk */ + gtk_init(NULL, NULL); + + /* Initialize evince */ + if (!ev_init()) + return FALSE; + ev_stock_icons_init(); + + evbp_is_initialized = TRUE; + return TRUE; +} + +static void +evbp_shutdown(void) +{ + evbp_debug(NULL); + + if (!evbp_is_initialized) + return; + + ev_shutdown(); + ev_stock_icons_shutdown(); + + evbp_is_initialized = FALSE; +} + +static NPError +evbp_new(NPMIMEType pluginType, NPP instance, uint16_t mode, + int16_t argc, char *argn[], char *argv[], + NPSavedData *saved) +{ + evbp_priv_t *priv; + + evbp_debug(NULL); + + /* create new private data */ + priv = npn_funcs->memalloc(sizeof(*priv)); + if (!priv) + return NPERR_OUT_OF_MEMORY_ERROR; + memset(priv, 0, sizeof(*priv)); + + /* link the structures */ + priv->npp = instance; + instance->pdata = priv; + + /* create new previewer */ + priv->pview = ev_previewer_new(); + + return NPERR_NO_ERROR; +} + +static NPError +evbp_destroy(NPP instance, NPSavedData** save) +{ + evbp_priv_t *priv = instance->pdata; + + evbp_debug(NULL); + + g_object_unref(priv->pview); + npn_funcs->memfree(instance->pdata); + instance->pdata = NULL; + + return NPERR_NO_ERROR; +} + +static NPError +evbp_set_window(NPP instance, NPWindow *window) +{ + evbp_priv_t *priv = instance->pdata; + GtkWidget *pview = priv->pview; + GdkNativeWindow id; + GtkWidget *plug; + + evbp_debug(NULL); + + /* If this is the same window we already have, don't create a + new plug */ + if (window == priv->window) { + evbp_debug("Same window; returning\n"); + return NPERR_NO_ERROR; + } + priv->window = window; + + /* Create a plug from the window id we were told about */ + id = (GdkNativeWindow)(unsigned long)window->window; + evbp_debug("Plugging previewer into window id %u\n", id); + plug = gtk_plug_new(id); + gtk_container_add(GTK_CONTAINER(plug), pview); + gtk_widget_show(pview); + gtk_widget_show(plug); + + return NPERR_NO_ERROR; +} + +static NPError +evbp_new_stream(NPP instance, NPMIMEType type, NPStream *stream, + NPBool seekable, uint16_t *stype) +{ + evbp_debug(NULL); + + /* fetch the url to a local file only */ + *stype = NP_ASFILEONLY; + + return NPERR_NO_ERROR; +} + +static NPError +evbp_destroy_stream(NPP instance, NPStream *stream, NPReason reason) +{ + evbp_debug(NULL); + + return NPERR_NO_ERROR; +} + +static int32_t +evbp_write_ready(NPP instance, NPStream *stream) +{ + evbp_debug(NULL); + + return 0; +} + +static int32_t +evbp_write(NPP instance, NPStream *stream, int32_t offset, int32_t len, + void *buffer) +{ + evbp_debug(NULL); + + return 0; +} + +static void +evbp_stream_as_file(NPP instance, NPStream *stream, const char *fname) +{ + evbp_priv_t *priv = instance->pdata; + EvPreviewer *pview = EV_PREVIEWER(priv->pview); + + evbp_debug(NULL); + + if (!g_file_test(fname, G_FILE_TEST_IS_REGULAR)) { + evbp_debug("Filename \"%s\" does not exist or is not a regular file", + fname); + return; + } + priv->filename = fname; + + ev_previewer_set_source_file(pview, fname); +} + +static void +evbp_print(NPP instance, NPPrint *platformPrint) +{ + evbp_debug(NULL); +} + +static int16_t +evbp_handle_event(NPP instance, void *event) +{ + evbp_debug(NULL); + + return 0; +} + +static void +evbp_url_notify(NPP instance, const char *url, NPReason reason, + void *notifyData) +{ + evbp_debug(NULL); +} + +static NPError +evbp_get_value(NPP instance, NPPVariable variable, void *value) +{ + NPError err = NPERR_NO_ERROR; + + evbp_debug(NULL); + + switch (variable) { + case NPPVpluginNameString: + *((char **)value) = EVBP_NAME; + break; + case NPPVpluginDescriptionString: + *((char **)value) = EVBP_DESCRIPTION; + break; + case NPPVpluginNeedsXEmbed: + /* Require XEmbed */ + *((PRBool *)value) = PR_TRUE; + break; + default: + err = NPERR_GENERIC_ERROR; + } + + return err; +} + +static NPError +evbp_set_value(NPP instance, NPNVariable variable, void *value) +{ + evbp_debug(NULL); + + return NPERR_GENERIC_ERROR; +} + +static NPError +save_npn_funcs(const NPNetscapeFuncs *funcs) +{ + evbp_debug(NULL); + + /* Check for valid structure and compatibility */ + if (!funcs) + return NPERR_INVALID_FUNCTABLE_ERROR; + if (funcs->version >> 8 > NP_VERSION_MAJOR) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + if (funcs->size < sizeof(npn_funcs)) + return NPERR_INVALID_FUNCTABLE_ERROR; + + npn_funcs = funcs; + return NPERR_NO_ERROR; +} + +static NPError +fill_npp_funcs(NPPluginFuncs *funcs) +{ + evbp_debug(NULL); + + if (!funcs) + return NPERR_INVALID_FUNCTABLE_ERROR; + + /* Fill the browser's table */ + funcs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; + funcs->size = sizeof(*funcs); + funcs->newp = evbp_new; + funcs->destroy = evbp_destroy; + funcs->setwindow = evbp_set_window; + funcs->newstream = evbp_new_stream; + funcs->destroystream = evbp_destroy_stream; + funcs->asfile = evbp_stream_as_file; + funcs->writeready = evbp_write_ready; + funcs->write = evbp_write; + funcs->print = evbp_print; + funcs->event = evbp_handle_event; + funcs->urlnotify = evbp_url_notify; + funcs->getvalue = evbp_get_value; + funcs->setvalue = evbp_set_value; + + return NPERR_NO_ERROR; +} + +NPError +NP_Initialize(NPNetscapeFuncs *nfuncs, NPPluginFuncs *pfuncs) +{ + NPError ret; + PRBool xembed = PR_FALSE; + NPNToolkitType toolkit = 0; + + evbp_debug(NULL); + + ret = save_npn_funcs(nfuncs); + if (ret != NPERR_NO_ERROR) + return ret; + + ret = fill_npp_funcs(pfuncs); + if (ret != NPERR_NO_ERROR) + return ret; + + /* Check that the browser supports XEmbed */ + ret = npn_funcs->getvalue(NULL, NPNVSupportsXEmbedBool, + (void *)&xembed); + if (ret != NPERR_NO_ERROR || xembed != PR_TRUE) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + /* Check that the toolkit is Gtk2 */ + ret = npn_funcs->getvalue(NULL, NPNVToolkit, (void *)&toolkit); + if (ret != NPERR_NO_ERROR || toolkit != NPNVGtk2) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + if (!evbp_initialize()) + return NPERR_MODULE_LOAD_FAILED_ERROR; + + return NPERR_NO_ERROR; +} + +char * +NP_GetPluginVersion(void) +{ + evbp_debug(NULL); + + return EVBP_VERSION; +} + +char * +NP_GetMIMEDescription(void) +{ + GString *mimes; + + evbp_debug(NULL); + + if (!evbp_initialize()) + return NULL; + + mimes = evbp_get_mime_description(); + if (evbp_mime_string) + g_free(evbp_mime_string); + evbp_mime_string = g_string_free(mimes, FALSE); + + return evbp_mime_string; +} + +NPError +NP_Shutdown(void) +{ + evbp_debug(NULL); + + if (evbp_mime_string) { + g_free(evbp_mime_string); + evbp_mime_string = NULL; + } + npn_funcs = NULL; + + evbp_shutdown(); + + return NPERR_NO_ERROR; +} + +NPError +NP_GetValue(void *instance, NPPVariable variable, void *value) +{ + evbp_debug(NULL); + + return evbp_get_value(NULL, variable, value); +} |