summaryrefslogtreecommitdiff
path: root/src/evbp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/evbp.c')
-rw-r--r--src/evbp.c383
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);
+}