--- a
+++ b/src/plugin.c
@@ -0,0 +1,533 @@
+/* 
+ * Copyright (C) 2000, 2001 the xine project
+ * 
+ * This file is part of xine, a unix video player.
+ * 
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * xine 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$
+ *
+ * xine plugin for mozilla 
+ *
+ */
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef XShmGetEventBase
+extern int XShmGetEventBase(Display *);
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <xine.h>
+#include <xine/video_out_x11.h>
+
+#include "npapi.h"
+
+typedef struct {
+
+  Window          window;
+  Window          video_window;
+  Display        *display;
+  GC              gc;
+  int             screen;
+  int             width,height;
+
+  pid_t           child_pid;
+
+  char            configfile[256];
+  config_values_t*config;
+  vo_driver_t    *vo_driver;
+  ao_driver_t    *ao_driver;
+  xine_t         *xine;
+  int             completion_event;
+  char            url[1024];
+
+} plugin_instance_t;
+
+
+char *NPP_GetMIMEDescription(void) {
+  return("mime/type:sample:Template Only");
+}
+
+NPError NPP_GetValue(void *future, NPPVariable variable, void *value){
+
+  NPError err = NPERR_NO_ERROR;
+
+  switch (variable) {
+  case NPPVpluginNameString:
+    *((char **)value) = "xine plugin";
+    break;
+  case NPPVpluginDescriptionString:
+    *((char **)value) =
+      "xine - a free video player";
+    break;
+  default:
+    err = NPERR_GENERIC_ERROR;
+  }
+  return err;
+}
+
+NPError NPP_Initialize(void) {
+  return NPERR_NO_ERROR;
+}
+
+
+void * NPP_GetJavaClass() {
+  return NULL;
+}
+
+void NPP_Shutdown(void) {
+}
+
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance,
+		uint16 mode,
+		int16 argc, char* argn[], char* argv[],
+		NPSavedData* saved) {
+
+  plugin_instance_t* this;
+  
+  if (instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+  
+  instance->pdata = NPN_MemAlloc(sizeof(plugin_instance_t));
+  
+  this = (plugin_instance_t*) instance->pdata;
+  
+  if (this != NULL)
+    return NPERR_NO_ERROR;
+  else
+    return NPERR_OUT_OF_MEMORY_ERROR;
+}
+
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+
+  plugin_instance_t* this;
+
+  if (instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  this = (plugin_instance_t*) instance->pdata;
+
+  /* PLUGIN DEVELOPERS:
+   *	If desired, call NP_MemAlloc to create a
+   *	NPSavedDate structure containing any state information
+   *	that you want restored if this plugin instance is later
+   *	recreated.
+   */
+
+  if (this != NULL) {
+    NPN_MemFree(instance->pdata);
+    instance->pdata = NULL;
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+
+
+NPError NPP_SetWindow(NPP instance, NPWindow* window) {
+
+  plugin_instance_t* this;
+  
+  if (instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+  
+  if (window == NULL)
+    return NPERR_NO_ERROR;
+  
+  this = (plugin_instance_t*) instance->pdata;
+  
+  this->window = (Window) window->window;
+
+  return NPERR_NO_ERROR;
+}
+
+void video_window_calc_dest_size (void *this_gen,
+				  int video_width, int video_height,
+				  int *dest_width, int *dest_height)  {
+  plugin_instance_t* this = (plugin_instance_t *) this_gen;
+
+  *dest_width  = this->width;
+  *dest_height = this->height;
+}
+
+void video_window_adapt_size (void *this_gen,
+			      int video_width, int video_height, 
+			      int *dest_x, int *dest_y,
+			      int *dest_width, int *dest_height) {
+
+  plugin_instance_t* this = (plugin_instance_t *) this_gen;
+
+  *dest_x      =   0;
+  *dest_y      =   0;
+  *dest_width  = this->width;
+  *dest_height = this->height;
+}
+
+static vo_driver_t *load_video_out_driver(plugin_instance_t *this) {
+
+  double             res_h, res_v;
+  x11_visual_t       vis;
+  char             **driver_ids;
+  int                i;
+  char              *video_driver_id;
+  vo_driver_t       *vo_driver;
+
+  vis.display           = this->display;
+  vis.screen            = this->screen;
+  vis.d                 = this->window;
+  res_h                 = (DisplayWidth  (this->display, this->screen)*1000 
+			   / DisplayWidthMM (this->display, this->screen));
+  res_v                 = (DisplayHeight (this->display, this->screen)*1000
+			   / DisplayHeightMM (this->display, this->screen));
+  vis.display_ratio     = res_h / res_v;
+
+  if (fabs(vis.display_ratio - 1.0) < 0.01) {
+    vis.display_ratio   = 1.0;
+  }
+
+  vis.calc_dest_size    = video_window_calc_dest_size;
+  vis.request_dest_size = video_window_adapt_size;
+  vis.user_data         = this;
+  
+  /* video output driver auto-probing */
+  driver_ids = xine_list_video_output_plugins (VISUAL_TYPE_X11);
+
+  /* Try to init video with stored information */
+  video_driver_id = this->config->lookup_str(this->config,
+					     "video_driver_name", NULL);
+  if(video_driver_id) {
+
+    vo_driver=xine_load_video_output_plugin(this->config, 
+					    video_driver_id,
+					    VISUAL_TYPE_X11,
+					    (void *) &vis);
+    if(driver_ids) {
+      free(driver_ids);
+      return vo_driver;
+    }
+  }
+    
+  i = 0;
+  while (driver_ids[i]) {
+	
+    video_driver_id = driver_ids[i];
+	
+    vo_driver = xine_load_video_output_plugin(this->config, 
+					      video_driver_id,
+					      VISUAL_TYPE_X11, 
+					      (void *) &vis);
+    if (vo_driver) {
+      this->config->set_str(this->config,"video_driver_name", video_driver_id);
+      if(driver_ids)
+	free(driver_ids);
+      return vo_driver;
+    }
+	
+    i++;
+  }
+  
+  return NULL;
+}
+
+static ao_driver_t *load_audio_out_driver(plugin_instance_t *this) {
+
+  ao_driver_t *ao_driver=NULL;
+  char        *audio_driver_id;
+  char       **driver_ids = xine_list_audio_output_plugins ();
+  int          i = 0;
+  
+  /* try to init audio with stored information */
+  audio_driver_id = this->config->lookup_str(this->config, "audio_driver_name", NULL);
+
+  if (audio_driver_id) 
+    return xine_load_audio_output_plugin(this->config, 
+					 audio_driver_id);
+
+
+  while ( (driver_ids[i] != NULL) && (ao_driver == NULL) ) {
+    audio_driver_id = driver_ids[i];
+    
+    ao_driver = xine_load_audio_output_plugin(this->config, 
+					      driver_ids[i]);
+    i++;
+  }
+  
+  return ao_driver;
+
+}
+  
+/*
+void event_listener (void *user_data, xine_event_t *event) {
+  
+  switch(event->type) { 
+  case XINE_EVENT_UI_CHANNELS_CHANGED:
+    break;
+
+  case XINE_EVENT_UI_SET_TITLE: 
+    {
+
+      xine_ui_event_t *uevent = (xine_ui_event_t *)event;
+    }
+    break;
+  case XINE_EVENT_PLAYBACK_FINISHED:
+    break;
+  case XINE_EVENT_NEED_NEXT_MRL:
+    {
+      xine_ui_event_t *uevent = (xine_ui_event_t *)event;
+
+      uevent->handled = 1;
+    }
+    break;
+  case XINE_EVENT_BRANCHED:
+    break;
+  }      
+  
+}
+*/
+
+void xine_proc (plugin_instance_t *this) {
+
+  XGCValues         values;
+  XWindowAttributes attr;
+
+  if (!XInitThreads ()) {
+    printf ("XInitThreads failed - looks like you don't have a thread-safe xlib.\n");
+    return;
+  } 
+
+  this->display = XOpenDisplay (NULL);
+
+  if (!this->display) {
+    printf ("XOpenDisplay failed!\n");
+    return;
+  }
+
+  XLockDisplay (this->display);
+
+  this->screen = DefaultScreen (this->display);
+
+  /*
+   * get size of window
+   */
+  XGetWindowAttributes (this->display, this->window,
+			&attr);
+  this->width = attr.width;
+  this->height = attr.height;
+
+  /*
+   * create our own video window
+   */
+
+  printf ("create window...\n");
+
+  this->video_window = XCreateSimpleWindow (this->display, this->window,
+					    0, 0, this->width, this->height, 1, 
+					    BlackPixel(this->display, this->screen),
+					    WhitePixel(this->display, this->screen));
+
+  printf ("select input...\n");
+
+  if (XShmQueryExtension (this->display) == True) {
+    this->completion_event = XShmGetEventBase (this->display) + ShmCompletion;
+  } else {
+    this->completion_event = -1;
+  }
+
+  XSelectInput (this->display, this->video_window,
+		StructureNotifyMask | ExposureMask | 
+		KeyPressMask | ButtonPressMask | PointerMotionMask);
+
+  /*
+   * generate and init a config "object"
+   */
+  snprintf (this->configfile, 255, "%s/.xinerc", getenv ("HOME"));
+  this->config = config_file_init (this->configfile);
+
+  this->vo_driver = load_video_out_driver(this) ;
+
+  if (!this->vo_driver) {
+    printf ("couldn't open video driver\n");
+    return;
+  }
+
+  this->ao_driver = load_audio_out_driver(this);
+
+  this->xine = xine_init (this->vo_driver, this->ao_driver,
+			  this->config);
+
+
+  values.foreground = BlackPixel (this->display, this->screen);
+  values.background = WhitePixel (this->display, this->screen);
+
+  this->gc = XCreateGC (this->display, this->video_window,
+			(GCForeground | GCBackground),
+			&values);
+	
+  XUnlockDisplay (this->display);
+
+  xine_play (this->xine, this->url, 0, 0);
+
+  while (1) {
+	
+    XEvent event;
+
+    XNextEvent (this->display, &event);
+
+    switch (event.type) {
+    case Expose:
+	  
+      if (event.xexpose.count != 0)
+	break;
+      
+      XLockDisplay (this->display);
+      XDrawRectangle (this->display, this->video_window,
+		      this->gc, 0,0,100,100);
+      XUnlockDisplay (this->display);
+
+      break;
+
+    }
+
+    if (event.type == this->completion_event) 
+      this->vo_driver->gui_data_exchange (this->vo_driver, 
+					  GUI_DATA_EX_COMPLETION_EVENT, 
+					  &event);
+  }
+
+}
+
+NPError NPP_NewStream(NPP instance,
+		      NPMIMEType type,
+		      NPStream *stream, 
+		      NPBool seekable,
+		      uint16 *stype) {
+
+  /* NPByteRange        range; */
+  plugin_instance_t *this;
+  int                pid;
+
+  if (instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+  
+  this = (plugin_instance_t*) instance->pdata;
+
+  strncpy(this->url,stream->url, 1024);
+
+  pid = fork ();
+
+  if ( pid ) 
+    this->child_pid = pid;
+  else {
+    xine_proc (this);
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+
+/* PLUGIN DEVELOPERS:
+ *	These next 2 functions are directly relevant in a plug-in which
+ *	handles the data in a streaming manner. If you want zero bytes
+ *	because no buffer space is YET available, return 0. As long as
+ *	the stream has not been written to the plugin, Navigator will
+ *	continue trying to send bytes.  If the plugin doesn't want them,
+ *	just return some large number from NPP_WriteReady(), and
+ *	ignore them in NPP_Write().  For a NP_ASFILE stream, they are
+ *	still called but can safely be ignored using this strategy.
+ */
+
+int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
+				   * mode so we can take any size stream in our
+				   * write call (since we ignore it) */
+
+int32 NPP_WriteReady(NPP instance, NPStream *stream) {
+
+  plugin_instance_t* this;
+  if (instance != NULL)
+    this = (plugin_instance_t*) instance->pdata;
+
+  return STREAMBUFSIZE;
+}
+
+
+int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) {
+
+  /*
+  if (instance != NULL) {
+    plugin_instance_t* this = (plugin_instance_t*) instance->pdata;
+  }
+  */
+
+  return len;		/* The number of bytes accepted */
+}
+
+
+NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) {
+
+  plugin_instance_t* this;
+
+  if (instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+  this = (plugin_instance_t*) instance->pdata;
+
+  return NPERR_NO_ERROR;
+}
+
+
+void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) {
+
+  plugin_instance_t* this;
+
+  if (instance != NULL)
+    this = (plugin_instance_t*) instance->pdata;
+}
+
+
+void NPP_Print(NPP instance, NPPrint* printInfo) {
+
+  if(printInfo == NULL)
+    return;
+
+  /*
+  if (instance != NULL) {
+    plugin_instance_t* this = (plugin_instance_t*) instance->pdata;
+	
+    if (printInfo->mode == NP_FULL) {
+
+      void* platformPrint =
+	printInfo->print.fullPrint.platformPrint;
+      NPBool printOne =
+	printInfo->print.fullPrint.printOne;
+			
+      printInfo->print.fullPrint.pluginPrinted = FALSE;
+
+    } else {	
+
+      NPWindow* printWindow =
+	&(printInfo->print.embedPrint.window);
+      void* platformPrint =
+	printInfo->print.embedPrint.platformPrint;
+    }
+  }
+  */
+}